fumingxia 发表于 2015-10-14 09:42:03

HQL语言入门


[*]登录 | 注册
[*]
[*]收藏成功确定收藏失败,请重新收藏确定标题标题不能为空网址标签摘要                                                                                                                                                                                                                公开                                                                                                                                          取消                            收藏            
[*]                                                                                                                                                                                                查看所有私信查看所有通知      暂没有新通知             和谐第一回复了您的帖子   11-20               麦田回复了您的评论       11-20            返回通知列表      下一条      上一条                        和谐第一回复了您的帖子"新注册的用户为何转载不了别人写的优秀文章??"                                                                  和谐第一                  :                  您问的是博客转载还论坛转载?不能转载时,相同提示什么?                                    11-20                  暂没有新通知查看其它 0 条                  麦田回复了您的评论你好,我想问怎么转载你写的文章,感觉还不错!                暂没有新通知查看其它 0 条            
[*]                                                                                                                                          分享资讯                      传PPT/文档                      提问题                      写博客                      传资源                      创建项目                      创建代码片            
[*]                                                                                                                                                                                          我是广西人编辑自我介绍,让更多人了解你                                                            帐号设置退出            
[*]                                                                                                                                                                                                    社区
                                             博客                     论坛                     下载                      技术问答                      极客头条                                                                                                                        服务
                                             CODE                     英雄会                     活动                     CSTO                     C币兑换                                                                                                                        俱乐部
                                             CTO俱乐部                     高校俱乐部            
                                                                               wsh900221的专栏
            
                                                                        
               
[*]                  目录视图               
[*]                  摘要视图               
[*]                  订阅                           
                                                               博客专家福利   2015年4月微软MVP申请    有奖征文--我亲历的京东发展史    参与迷你编程马拉松赢iPhone 6                                                                                        HQL语言入门            
                  分类:            数据库mysql             2014-08-26 16:48    39人阅读    评论(0)    收藏    举报          目录(?)[+]

[*]简单属性查询重要
[*]单一属性查询
[*]多个属性查询
[*]多个属性查询返回Student
[*]使用别名

[*]实体对象查询重要
[*]条件查询重要
[*]hibernate直接使用sql语句查询
[*]外置命名查询
[*]查询过滤器
[*]分页查询重要
[*]对象导航查询重要
[*]连接查询重要
[*]统计查询重要
[*]DML风格的操作尽量少用因为和缓存不同步
  SQL和HQL只有一个字母只差,一个是结构化查询语言,一个是Hibernate查询语言,HQL延用了SQL中的语法、关键词。
  HQL是Hibernate Query Language的简称,也就是说HQL是一种Hibernate查询语言,所以它在Hibernate世界里应用很方便。HQL是完全面向对象的查询语句,查询功能非常强大,具备多态、关联等特性。链接一篇关于HQL详细介绍的文章《HQL: Hibernate查询语言》,里面讲的内容很详细!
  HQL简单介绍

  

  HQL查询依赖于Query类,每个Query实例对应一个查询对象。使用HQL查询可按如下步骤进行:
      1)获取Hibernate Session对象;
      2)编写HQL语句;
      3)以HQL语句作为参数,调用Session的createQuery方法创建查询对象;
      4)如果HQL语句包含参数,调用Query的setXxx方法为参数赋值;
      5)调用Query对象的list等方法遍历查询结果。

  

  
  进入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 = &quot;select o from o &quot;
+ &quot;Order as o join o.products as p &quot;
+ &quot;where o.priceTotal > :priceTotalLower&quot;
+ &quot;and o.priceTotal< :priceTotalUpper&quot;;

Query q = sess.createQuery(query);
// 将两个参数传入HQL中
q.setDouble(&quot;priceTotalLower&quot;, Double.parseDouble(lower));
q.setDouble(&quot;priceTotalUpper&quot;, 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。
  =========================================================================================================================
  
1、简单属性查询【重要】
  
      *单一属性查询,返会属性结果集列表,元素类型和实体类中相应的类型一致
      *多个属性查询,多个属性查询返会对象数组,对象数组的长度取决于属性的个数,对象数组中元素的类型取决于属性在实体类中的类型
      *如果认为返会数组不够对象化,可以使用hql动态实例化Student对象
  
单一属性查询
view plaincopy
[*]//返回结果集属性列表,元素类型和实体类中的属性类型一致
[*]
[*]Liststudents = session.createQuery(&quot;select name from Student&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Stringname = (String)iter.next();
[*]
[*]System.out.println(name);
[*]
[*]}
  
  
多个属性查询
view plaincopy
[*]//查询多个属性,返回对象数组集合
[*]
[*]//数组元素的类型与查询的属性类型一致
[*]
[*]//数组的长度与select中查询的属性个数一致
[*]
[*]Liststudents = session.createQuery(&quot;select id, name fromStudent&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  

  
多个属性查询,返回Student
view plaincopy
[*]//可以使用hql返回Student对象
[*]
[*]//需要提供构造函数
[*]
[*]Liststudents = session.createQuery(&quot;select new Student(id, name) fromStudent&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Studentstudent = (Student)iter.next();
[*]
[*]System.out.println(student.getId()+ &quot;, &quot; + student.getName());
[*]
[*]}
  
  
使用别名
view plaincopy
[*]//可以使用别名
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Students&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  

  
view plaincopy
[*]//可以采用as命名别名
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student ass&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  

  
  
2、实体对象查询【重要】
      * N + 1问题,就是发出了N+1条sql语句
     1:首先发出查询对象id列表的语句
     N:根据id到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的sql语句
     
      *list和iterate的区别?
     list:默认情况下list每次都会发出sql语句,list会将数据放到缓存中,而不利用缓存
     iterate:默认情况下iterate利用缓存,如果缓存中不存在会出现N+1问题
view plaincopy
[*]//返回Student对象的集合
[*]
[*]//可以忽select关键字
[*]
[*]Liststudents = session.createQuery(&quot;from Student&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Studentstudent = (Student)iter.next();
[*]
[*]System.out.println(student.getName());
[*]
[*]}
[*]
[*]   
[*]
[*]/**
[*]
[*] * 采用list查询实体对象会发出一条查询语句,取得实体对象数据
[*]
[*] *   
[*]
[*] * Hibernate: select student0_.id as id0_,student0_.name as name0_,   
[*]
[*] * student0_.createTime as createTime0_,student0_.classesid as classesid0_   
[*]
[*] * from t_student student0_
[*]
[*] */
[*]
[*]Liststudents = session.createQuery(&quot;from Student&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Studentstudent = (Student)iter.next();
[*]
[*]System.out.println(student.getName());
[*]
[*]}
  

3、条件查询【重要】
      *可以采用拼字符串的方式传递参数
view plaincopy
[*]//可以拼串
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheres.name like '%0%'&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  

      * 可以采用?来传递参数(索引从0开始)
view plaincopy
[*]//可以使用?方式传递参数
[*]
[*]//索引从0开始,不同于jdbc从1开始
[*]
[*]//值能使用单引号引起来
[*]
[*]//Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheres.name like ?&quot;).list();
[*]
[*]//                        Queryquery= session.createQuery(&quot;selects.id, s.name from Student s where s.name like ?&quot;);
[*]
[*]//                        query.setParameter(0,&quot;%0%&quot;);
[*]
[*]//                        Liststudents = query.list();
[*]
[*]   
[*]
[*]//方法链编程,建议采用此种方式
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheres.name like ?&quot;)
[*]
[*].setParameter(0,&quot;%0%&quot;)
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  

      * 可以采用:参数名 来传递参数
  
  
view plaincopy
[*]//可以采用:参数名 的方式传递参数
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheres.name like :myname&quot;)
[*]
[*].setParameter(&quot;myname&quot;,&quot;%0%&quot;)
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  

  
      *如果传递多个参数,可以采用setParamterList方法
view plaincopy
[*]//采用?方式,查询学号为1,2,3,4,5的学生
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheres.id in(?, ?, ?, ?, ?)&quot;)
[*]
[*].setParameter(0,1)
[*]
[*].setParameter(1,2)
[*]
[*].setParameter(2,3)
[*]
[*].setParameter(3,4)
[*]
[*].setParameter(4,5)
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  

      *在hql中可以使用数据库的函数,如:date_format
  
view plaincopy
[*]//采用:参数名 方式,查询学号为1,2,3,4,5的学生
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheres.id in(:ids)&quot;)
[*]
[*].setParameterList(&quot;ids&quot;,new Object[]{1, 2, 3, 4, 5})
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
[*]
[*]//查询2009-08的学生,可以调用mysql的日期格式化函数
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheredate_format(s.createTime, '%Y-%m')=?&quot;)
[*]
[*].setParameter(0,&quot;2009-08&quot;)
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
[*]
[*]   
[*]
[*]SimpleDateFormatsdf = new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;);
[*]
[*]//查询2009-08-01到2009-08-20的学生,可以调用mysql的日期格式化函数
[*]
[*]Liststudents = session.createQuery(&quot;select s.id, s.name from Student s wheres.createTime between ? and ?&quot;)
[*]
[*].setParameter(0,sdf.parse(&quot;2009-08-01 00:00:00&quot;))
[*]
[*].setParameter(1,sdf.parse(&quot;2009-08-20 23:59:59&quot;))
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  
4、hibernate直接使用sql语句查询
view plaincopy
[*]Liststudents = session.createSQLQuery(&quot;select * from t_student&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  
5、外置命名查询
      * 在映射文件中使用<query>标签来定义hql
      * 在程序中使用session.getNamedQuery()方法得到hql查询串
     
view plaincopy
[*]      
[*]
[*]<querynamequeryname=&quot;queryStudent&quot;>
[*]
[*]<![CDATA[
[*]
[*]selects from Student s where s.id <?
[*]
[*]]]>
[*]
[*]</query>
  
view plaincopy
[*]List students =session.getNamedQuery(&quot;queryStudent&quot;)
[*]
[*].setParameter(0,10)
[*]
[*].list();
[*]
[*]for (Iteratoriter=students.iterator(); iter.hasNext();) {
[*]
[*]Studentstudent = (Student)iter.next();
[*]
[*]System.out.println(student.getName());
[*]
[*]}
  
  
6、查询过滤器
      *在映射文件中定义过滤器参数
      *在类的映射中使用过滤器参数
      *在程序中必须显示的启用过滤器,并且为过滤器参数赋值
view plaincopy
[*]<filter-defnamefilter-defname=&quot;testFilter&quot;>
[*]
[*]<filter-paramtypefilter-paramtype=&quot;integer&quot; name=&quot;myid&quot;/>
[*]
[*]</filter-def>
view plaincopy
[*]session.enableFilter(&quot;testFilter&quot;)
[*]
[*].setParameter(&quot;myid&quot;,10);
[*]
[*]Liststudents = session.createQuery(&quot;from Student&quot;).list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Studentstudent = (Student)iter.next();
[*]
[*]System.out.println(student.getName());
[*]
[*]}
  
  
7、分页查询【重要】
      *setFirstResult(),从0开始
      *setMaxResults(),每页显示的记录数
view plaincopy
[*]Liststudents = session.createQuery(&quot;from Student&quot;)
[*]
[*].setFirstResult(1)
[*]
[*].setMaxResults(2)
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Studentstudent = (Student)iter.next();
[*]
[*]System.out.println(student.getName());
[*]
[*]}
  
  
8、对象导航查询【重要】
  
view plaincopy
[*]Liststudents = session.createQuery(&quot;from Student s where s.classes.name like'%2%'&quot;)
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Studentstudent = (Student)iter.next();
[*]
[*]System.out.println(student.getName());
[*]
[*]}
  

9、连接查询【重要】
      * 内连接
      * 外连接(左连接/右连接)left join   right join
view plaincopy
[*]Liststudents = session.createQuery(&quot;select c.name, s.name from Student s joins.classes c&quot;)
[*]
[*].list();
[*]
[*]for(Iterator iter=students.iterator(); iter.hasNext();) {
[*]
[*]Object[]obj = (Object[])iter.next();
[*]
[*]System.out.println(obj+ &quot;, &quot; + obj);
[*]
[*]}
  
10、统计查询【重要】
view plaincopy
[*]Longcount = (Long)session.createQuery(&quot;select count(*) fromStudent&quot;).uniqueResult();

11、DML风格的操作(尽量少用,因为和缓存不同步)      
view plaincopy
[*]@SuppressWarnings(&quot;unused&quot;)
[*]
[*]//Studentstudent = (Student)session.load(Student.class, 1);
[*]
[*]Studentstudent = (Student)session.get(Student.class, 1);
[*]
[*]   
[*]
[*]//数据库表中更新了,但缓存不更新
[*]
[*]//所以一般不建议使用,除非有必须,如遇到性能问题
[*]
[*]session.createQuery(&quot;updateStudent s set s.name=? where s.id<?&quot;)
[*]
[*].setParameter(0,&quot;王五&quot;)
[*]
[*].setParameter(1,5)
[*]
[*].executeUpdate();
[*]
[*]   
[*]
[*]//student= (Student)session.load(Student.class, 1);
[*]
[*]student= (Student)session.get(Student.class, 1);
[*]
[*]System.out.println(&quot;student.name=&quot;+ student.getName());
页: [1]
查看完整版本: HQL语言入门