服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

另类查询 hibernate hql 深度历险


  传统的sql语言采用的是结构化的查询方法,而这种方法对于查询以对象形式存在的数据却无能为力。幸运的是,hibernate为我们提供了一种语法类似于sql的语言,hibernate查询语言(hql),和sql不同的是,hql是一种面向对象的查询语言,它可以查询以对象形式存在的数据。因此,本文就hql如何工作以及如何使用hql展开了深入的讨论。

  sql本身是非常强大的。当sql的这种强大和处理面向对象数据的能力相结合时,就产生了hql。和sql一样,hql提供了丰富的查询功能,如投影查询、聚合函数、分组和约束。任何复杂的sql都可以映射成hql。

  本文的第一部分将讨论hql的简单用法。第二部分将讨论在hql中如何根据上下文关系进行查询。在第三部分将以一个例子来说明如何在实际应用中使用hql。

  进入hql世界

  一个orm框架是建立在面向对象的基础上的。最好的例子是hibernate如何提供类sql查询。虽然hql的语法类似于sql,但实际上它的查询目标是对象。hql拥有面向对象语言的所有的特性,这其中包括多态、继承和组合。这就相当于一个面向对象的sql,为了提供更强大的功能,hql还提供了很多的查询函数。这些函数可以被分为四类:

  1. 投影函数

  2. 约束函数

  3. 聚合函数

  4. 分组函数

  使用hql可以建立简单的查询,也可以建立更复杂的查询。在本文中并不讨论那些非常复杂的查询,如含有子查询和很多连接的查询。本文只讨论连接两个表的查询。现在让我们开始接近hql吧!

  投影

  如谓投影,就是一个可以访问的对象或对象的属性。在hql中,可以使用from和select子句来完成这个工作。

  from子句返回指定的类的所有实例。如from order将返回order类的所有实例。换句话说,以上的查询相当于以下的sql语句:

select * from order

  from 是最简单的查询子句。from后面可以跟一个或多个类名(类名也可以带有别名)。为了得到order和product的所有实例,可以使用如下的查询:

from order, product

  和类名一样,别名也可以在from后使用,如下代码如示:

from order as o, product p

  当查询很复杂时,加入别名可以减少语句的长度。我们可以看看如下的sql语句:

select o.*, p.* from order o, product p where o.order_id = p.order_id

  我们可以很容易看出,上面的查询是一对多的关系。在hql中相当于一个类中包含多个其它类的实例。因此,以上的sql写成hql就是:

from order as o inner join o.products as product

  现在让我们考虑另外一个从表中得到指定属性的情况。这就是最常用的select子句。这在hql中的工作方式和sql中一样。而在hql中,如果只是想得到类的属性的话,select语句是最后的选择。以上的sql可以使用select子句改成如下的hql语句:

select product from order as o inner join o.products as product

  以上的hql语句将返回order中的所有products实例。如果要得到对象的某一个属性,可以将hql语句写成如下的形式:

select product.name from order as o inner join o.products as product

  如果要得到多个对象的属性,可以将hql语句写成如下形式:

select o.id, product.name from order as o inner join o.products as product

  接下来,我们将进入下一个议题。假设我们需要根据某些条件得到数据。那么以上所述的hql语句将无法满足需求。为了达到这一目的,我们就要用到下面将要讨论的约束子句。 约束

  从以上可知,投影返回的是所有的数据。但在大多数时候我们并不需要这么多数据。这就需要对数据进行过滤。在hql中过滤数据的子句和sql一样,也是where。它的语法类似于sql,通过where子句,可以对行进行过滤。我们可以看看下面的sql语句:

select * from orders where id = ‘1234’

  这条查询语句返回了id等于1234的所有的字段。和这条sql对等的是下面的hql语句:

select o from order o where o.id=’1234’

  从以上两条语句可以看出,它们的where子句非常相似。而它们唯一的不同是sql操作的是记录,而hql操作的是对象。在hql中,除了where子句可以过滤数据外,having子句也可以做到这一点(关于having子句的详细内容我将在分组部分讨论)。投影和约束是两个基本的操作,这两个操作再加上聚合函数的话,那hql将变得更加强大。下面我们就来讨论什么是聚合。

  聚合

  上述的查询都是将每一个记录(对象)当做一个单位,而如果使用聚合,可以将一类记录(对象)当做一个单位。然后再对每一类的记录(对象)进行一系列地操作,如对某一列取平均值、求和、统计行数等等。hql支持以下的聚合函数:

  1. avg(…), sum(…)
  2. min(…), max(…)
  3. count(*), count(…), count(distinct…), count(all…)

  以上的聚合函数都返回数值类型。这些操作都可以在select子句中使用,如下所示:

select max(o.pricetotal) + max(p.price) from order o join o.products p group by o.id

  以上的hql语句返回了两个值的和:orders表中的pricetotal的最大值和products表中的price的最大值之和。我们还可以使用having子句对分组进行过滤。如我们想按id统计pricetotal小于1000的数量可按如下的hql语句去实现:

select count(o) from order o having o.pricetotal < 1000 group by o.id

  我们还可以将聚合函数和having子句一起使用。如我们要按products表的id统计price小于amount的平均数的产品数量,hql语句如下:

select count(p) from product p having p.price < avg(amount) group by p.id

  从上面的一系列的hql语句可以看出,所有通过sql实现的,都可以通过hql来实现。

  分组

  在上一部分,已经涉及到了分组的概念。分组操作的是行的集合。它根据某一列(属性)对记录集进行分组。这一切是通过group子句实现的。如下的例子描述了group子句的一般用法。

select count(o) from order o having o.pricetotal >= 1200 and o.pricetotal <= 3200 group by o.id

  hql中的分组和sql中的分组类似。总之,除了一些对sql的特殊扩展外,其它所有的sql功能都可以使用hql描述。在接下来的部分,让我们举例说明如何在java中使用hql。 在java中使用hql

  到现在为止,我们已经学习了hql的基本用法。接下来我们举一个例子来说明如何在java中使用hql。下面的例子只给出了主要的部分,由于本文只是讨论hql的用法,因此,关于hibernate的一些设置和在main()函数中调用hibernate的部分并未给出,读者可以参考相关的文当。现在让我们看看下面的例子。

  下面是必须引用的包
 
import java.util.list;
import org.hibernate.*;
import org.hibernate.cfg.*
import com.order;

  下面是类的声明

public class myorder
{
… …
}

  下面让我们来实现myorder类的构造函数

public class myorder
{
sessionfactory sf;

public myorder()
{
configuration cfg = new configuration().addclass(order.class);
sf = cfg.buildsessionfactory();
}
… …
}

  下面的getorder函数根据pricetotal的区间值返回order对象。

public class myorder
{
…. ….
public order getorder(string lower, string upper)
{
// 打开一个会话
session sess = sf.opensession();
// hql语句
string query = "select o from o "
+ "order as o join o.products as p "
+ "where o.pricetotal > :pricetotallower"
+ "and o.pricetotal< :pricetotalupper";

query q = sess.createquery(query);
// 将两个参数传入hql中
q.setdouble("pricetotallower", double.parsedouble(lower));
q.setdouble("pricetotalupper", double.parsedouble(upper));

list list = q.list();

order o=(order)list.iterator.next();

return o;

}
… …
}

  下面的main函数将测试myorder类

public class myorder
{
… …
public static void main(string args[])
{
order o=myorder().getorder(“100”, “300”);
system.out.println(“id=”+ o.id);
… …
}
}

  小结

  上述的代码演示了如何在java中使用hql,但hql还有两点需要注意一下:

  1. hql并不区分字母的大小写,但在hql中的java类和属性名必须和实际的类和属性名一致。如select和select之间可以互换,但order和order却代表不同的含义。

  2. 如果hql中引用的类未被导入,在hql中必须引用具体的包。如本例中,如果com.order未被导入,在hql中必须将order写成com.order。

扫描关注微信公众号