hibernate查询

 hibernate查询语言hql

在hql中关键字不区分大小写,但是属性和类名区分大小写

1、简单属性查询【重要】
 * 单一属性查询,返回结果集属性列表,元素类型和实体类中相应的属性类型一致
 * 多个属性查询,返回的集合元素是对象数组,数组元素的类型和对应的属性在实体类中的类型一致
    数组的长度取决与select中属性的个数
 * 如果认为返回数组不够对象化,可以采用hql动态实例化Student对象
 

 

  1. //返回结果集属性列表,元素类型和实体类中相应的属性类型一致  
  2. List students = session.createQuery("select name from Student").list();  
  3.   
  4. //查询多个属性,其集合元素是对象数组  
  5. //数组元素的类型和对应的属性在实体类中的类型一致  
  6. //数组的长度取决与select中属性的个数  
  7. List students = session.createQuery("select id, name from Student").list();  
  8.       
  9. //如果认为返回数组不够对象化,可以采用hql动态实例化Student对象  
  10. //此时list中为Student对象集合  
  11. List students = session.createQuery("select new Student(id, name) from Student").list();  
  12.   
  13. //可以使用别名  
  14. List students = session.createQuery("select s.id, s.name from Student s").list();  
  15.   
  16.   
  17.             //可以使用as命名别名  
  18.             List students = session.createQuery("select s.id, s.name from Student as s").list();  

 

2、实体对象查询【重要】
 * N + 1问题,在默认情况下,使用query.iterate查询,有可以能出现N+1问题
   所谓的N+1是在查询的时候发出了N+1条sql语句
   1: 首先发出一条查询对象id列表的sql
   N: 根据id列表到缓存中查询,如果缓存中不存在与之匹配的数据,那么会根据id发出相应的sql语句
 * list和iterate的区别?
  * list每次都会发出sql语句,list会向缓存中放入数据,而不利用缓存中的数据
  * iterate:在默认情况下iterate利用缓存数据,但如果缓存中不存在数据有可以能出现N+1问题
 

 

  1. //返回Student对象的集合  
  2. //可以忽略select  
  3. List students = session.createQuery("from Student").list();  
  4.   
  5. //返回Student对象的集合  
  6. //可以忽略select,表可以使用别名  
  7. List students = session.createQuery("from Student s").list();  
  8.   
  9. //返回Student对象的集合  
  10. //可以忽略select,表可以使用as命名别名  
  11. List students = session.createQuery("from Student as s").list();  
  12.           
  13. //返回Student对象的集合  
  14. //使用select查询实体对象,必须采用别名  
  15. List students = session.createQuery("select s from Student as s").list();  
  16.   
  17. //不支持select * from .....这样的查询语句  
  18. List students = session.createQuery("select * from Student").list();  
  19.   
  20. /** 
  21.  * 采用list查询发出一条查询语句,取得Student对象数据、 
  22.  *  
  23.  * Hibernate: select student0_.id as id1_, student0_.name as name1_,  
  24.  * student0_.createTime as createTime1_, student0_.classesid as classesid1_  
  25.  * from t_student student0_ 
  26.  *  
  27.  */  
  28. List students = session.createQuery("from Student").list();  
  29.   
  30. /** 
  31.  * 出现N+1问题 
  32.  *  
  33.  * 1:发出查询id列表的sql 
  34.  *   Hibernate: select student0_.id as col_0_0_ from t_student student0_ 
  35.  *  
  36.  * N:在依次发出根据id查询Student对象的sql 
  37.  * Hibernate: select student0_.id as id1_0_, student0_.name as name1_0_,  
  38.  * student0_.createTime as createTime1_0_, student0_.classesid as classesid1_0_  
  39.  * from t_student student0_ where student0_.id=? 
  40.  *   
  41.  */  
  42. Iterator iter = session.createQuery("from Student").iterate();  
  43.   
  44. /** 
  45.  * 不会出现N+1问题 
  46.  *  
  47.  * 因为list操作已经将Student对象放到了一级缓存中,所以再次使用iterate操作的时候 
  48.  * 它首先发出一条查询id列表的sql,在根据id到缓存中去数据,只有在缓存中找不到相应的 
  49.  * 数据时,才会发出sql到<a href="http://lib.csdn.net/base/mysql" class='replace_word' title="MySQL知识库" target='_blank' style='color:#df3434; font-weight:bold;'>数据库</a>中查询 
  50.  *  
  51. */  
  52.   
  53. /** 
  54.  * 再次发出查询sql 
  55.  *  
  56.  * 在默认情况下list每次都会向数据库发出查询对象的sql,除非配置查询缓存,所以下面的list操作 
  57.  * 虽然在一级缓存中已经有了对象数据,但list默认情况下不会利用缓存,而再次发出sql 
  58.  *  
  59.  * 默认情况下,list会向缓存中放入数据,但不会利用数据 
  60.  *  
  61.  */  
  62. students = session.createQuery("from Student").list();  

 
3、条件查询【重要】 
 * 可以采用拼字符串的方式传递参数
 * 可以采用 ?来传递参数(索引从0开始)
 * 可以采用 :参数名 来传递参数
 * 如果传递多个参数,可以采用setParamterList方法
 * 在hql中可以使用数据库的函数,如:date_format
 
  1. //可以拼字符串  
  2. List students = session.createQuery("select s.id, s.name from Student s where s.name like '%1%'").list();  
  3.   
  4. //Query query = session.createQuery("select s.id, s.name from Student s where s.name like ?");  
  5. //query.setParameter(0, "%1%");  
  6. //List students = query.list();  
  7.               
  8. //可以使用?方式传递参数  
  9. //参数的索引从0开始  
  10. //传递的参数值,不用单引号引起来  
  11. //注意方法链编程  
  12. List students = session.createQuery("select s.id, s.name from Student s where s.name like ?")  
  13.             .setParameter(0"%1%")  
  14.             .list();  
  15.   
  16. //使用 :参数名称 的方式传递参数值  
  17. List students = session.createQuery("select s.id, s.name from Student s where s.name like :myname")  
  18.                .setParameter("myname""%1%")  
  19.                .list();  
  20.   
  21. //使用 :参数名称 的方式传递参数值  
  22. List students = session.createQuery("select s.id, s.name from Student s where s.name like :myname and s.id=:myid")  
  23.                .setParameter("myname""%1%")  
  24.                .setParameter("myid"12)  
  25.                .list();  
  26.   
  27. //支持in,需要使用setParameterList进行参数传递  
  28. List students = session.createQuery("select s.id, s.name from Student s where s.id in(:myids)")  
  29.             .setParameterList("myids"new Object[]{12345})  
  30.             .list();  
  31.               
  32. //查询2008年2月创建的学生  
  33. List students = session.createQuery("select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?")  
  34.             .setParameter(0"2008-02")  
  35.             .list();  
  36.   
  37. //查询2008-01-10到2008-02-15创建的学生  
  38. List students = session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?")  
  39.             .setParameter(0, sdf.parse("2008-01-10 00:00:00"))  
  40.             .setParameter(1, sdf.parse("2008-02-15 23:59:59"))  
  41.             .list();  
 
   
4、hibernate也支持直接使用sql进行查询

 

  1. List students = session.createSQLQuery("select * from t_student").list();  
  2. for (Iterator iter=students.iterator(); iter.hasNext();) {  
  3.         Object[] obj = (Object[])iter.next();  
  4.     System.out.println(obj[0] + "," + obj[1]);  
  5. }  
  

 

 

5、外置命名查询
 * 在映射文件中采用<query>标签来定义hql
 * 在程序中采用session.getNamedQuery()方法得到hql查询串
 参见:Student.hbm.xml、NameQueryTest.java
 

  1. <query name="searchStudents">  
  2.     <!--[CDATA[  
  3.     SELECT s FROM Student s where s.id<?  
  4.     ]]-->  
  5. </query>  
  6.   
  7. List students = session.getNamedQuery("searchStudents")  
  8.                    .setParameter(010)  
  9.                .list();  


6、查询过滤器 
 * 在映射文件中定义过滤器参数
 * 在类的映射中使用这些参数
 * 在程序中启用过滤器
 

 

  1.     <class name="com.bjsxt.hibernate.Student" table="t_student">  
  2.         <id name="id">  
  3.             <generator class="native"/>  
  4.         </id>  
  5.         <property name="name"/>  
  6.         <property name="createTime"/>  
  7.         <many-to-one name="classes" column="classesid"/>  
  8.         <filter name="filtertest" condition="id < :myid"/>  
  9.     </class>    
  10.   
  11. <filter-def name="filtertest">  
  12.         <filter-param name="myid" type="integer"/>  
  13. </filter-def>   
  14.   
  15. session.enableFilter("filtertest").setParameter("myid"10);      
  16.               
  17. List students = session.createQuery("from Student").list();  
 
 
7、分页查询【重要】 
 * setFirstResult(),从0开始
 * setMaxResults,每页显示多少条数据
 参见:PageQueryTest.java

 

  1. List students = session.createQuery("from Student")  
  2.             .setFirstResult(1)  
  3.             .setMaxResults(2)  
  4.             .list();  
 
    
8、对象导航查询,在hql中采用 . 进行导航【重要】
 参见:ObjectNavQueryTest.java
 
  1. List students = session.createQuery("select s.name from Student s      where s.classes.name like '%1%'").list();  


9、连接查询【重要】
 * 内连
 * 外连接(左连接/右连接) 
 
 

  1. //List students = session.createQuery("select c.name, s.name from Student s join s.classes c").list();  
  2. List students = session.createQuery("select c.name, s.name from Student s inner join s.classes c").list();  


10、统计查询【重要】
 参见:StatQueryTest.java
 

  1. //List students =session.createQuery("select count(*) from Student").list();  
  2. //Long count = (Long)students.get(0);  
  3. //System.out.println(count);  
  4.   
  5. Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();  


11、DML风格的操作(尽量少用,因为和缓存不同步)
 

 

  1. session.createQuery("update Student s set s.name=? where s.id < ?")  
  2.                     .setParameter(0"李四")  
  3.                     .setParameter(15)  
  4.                     .executeUpdate(); 

12.get/load

       

一.load加载方式

当使用load方法来得到一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象,即:当我们使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的id值,只有当我们要使用这个对象,得到其它属性时,这个时候才会发出sql语句,从数据库中去查询我们的对象

       session = HibernateUtil.openSession();
            /*
             * 通过load的方式加载对象时,会使用延迟加载机制,此时并不会发出sql语句,只有当我们需要使用的时候才会从数据库中去查询
             */
            User user = (User)session.load(User.class, 2);

我们看到,如果我们仅仅是通过load来加载我们的User对象,此时从控制台我们会发现并不会从数据库中查询出该对象,即并不会发出sql语句,但如果我们要使用该对象时:

      session = HibernateUtil.openSession();
      User user = (User)session.load(User.class, 2);
      System.out.println(user);

此时我们看到控制台会发出了sql查询语句,会将该对象从数据库中查询出来:

Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
User [id=2, username=aaa, password=111, born=2013-10-16 00:14:24.0]

这个时候我们可能会想,那么既然调用load方法时,并不会发出sql语句去从数据库中查出该对象,那么这个User对象到底是个什么对象呢?

其实这个User对象是我们的一个代理对象,这个代理对象仅仅保存了id这个属性:

复制代码
      session = HibernateUtil.openSession();
            /*
             * 通过load的方式加载对象时,会使用延迟加载机制,此时得到的User对象其实是一个
             * 代理对象,该代理对象里面仅仅只有id这个属性
             */
            User user = (User)session.load(User.class, 2);
            System.out.println(user.getId());

      console:  2
复制代码

我们看到,如果我们只打印出这个user对象的id值时,此时控制台会打印出该id值,但是同样不会发出sql语句去从数据库中去查询。这就印证了我们的这个user对象仅仅是一个保存了id的代理对象,但如果我需要打印出user对象的其他属性值时,这个时候会不会发出sql语句呢?答案是肯定的:

复制代码
            session = HibernateUtil.openSession();
            /*
             * 通过load的方式加载对象时,会使用延迟加载机制,此时得到的User对象其实是一个
             * 代理对象,该代理对象里面仅仅只有id这个属性
             */
            User user = (User)session.load(User.class, 2);
            System.out.println(user.getId());
            // 如果此时要得到user其他属性,则会从数据库中查询
            System.out.println(user.getUsername());            
复制代码

此时我们看控制台的输出:

2
Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
aaa

相信通过上述的几个例子,大家应该很好的了解了load的这种加载对象的方式了吧。

二、get加载方式

相对于load的延迟加载方式,get就直接的多,当我们使用session.get()方法来得到一个对象时,不管我们使不使用这个对象,此时都会发出sql语句去从数据库中查询出来:

       session = HibernateUtil.openSession();
            /*
             * 通过get方法来加载对象时,不管使不使用该对象,都会发出sql语句,从数据库中查询
             */
            User user = (User)session.get(User.class, 2);

此时我们通过get方式来得到user对象,但是我们并没有使用它,但是我们发现控制台会输出sql的查询语句:

Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?

因此我们可以看到,使用load的加载方式比get的加载方式性能要好一些,因为load加载时,得到的只是一个代理对象,当真正需要使用这个对象时再去从数据库中查询。

三、使用get和load时的一些小问题

当了解了load和get的加载机制以后,我们此时来看看这两种方式会出现的一些小问题:

①如果使用get方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报NullPointException的异常

        session = HibernateUtil.openSession();
            /*
             * 当通过get方式试图得到一个id不存在的user对象时,此时会报NullPointException异常
             */
            User user = (User)session.get(User.class, 20);
            System.out.println(user.getUsername());

此时我们看控制台的输出信息,会报空指针的异常:

Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
java.lang.NullPointerException  .........

这是因为通过get方式我们会去数据库中查询出该对象,但是这个id值不存在,所以此时user对象是null,所以就会报NullPointException的异常了。

②如果使用load方式来加载对象,当我们试图得到一个id不存在的对象时,此时会报ObjectNotFoundException异常

复制代码
      session = HibernateUtil.openSession();
            /*
             * 当通过get方式试图得到一个id不存在的user对象时,此时会报ObjectNotFoundException异常
             */
            User user = (User)session.load(User.class, 20);
            System.out.println(user.getId());
            System.out.println(user.getUsername());
复制代码

我们看看控制台的输出:

20
Hibernate: select user0_.id as id0_0_, user0_.username as username0_0_, user0_.password as password0_0_, user0_.born as born0_0_ from user user0_ where user0_.id=?
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.xiaoluo.bean.User#20]......

为什么使用load的方式和get的方式来得到一个不存在的对象报的异常不同呢??其原因还是因为load的延迟加载机制,使用load时,此时的user对象是一个代理对象,仅仅保存了当前的这个id值,当我们试图得到该对象的username属性时,这个属性其实是不存在的,所以就会报出ObjectNotFoundException这个异常了。

org.hibernate.LazyInitializationException异常

接下来我们再来看一个例子:

复制代码
public class UserDAO
{
    public User loadUser(int id)
    {
        Session session = null;
        Transaction tx = null;
        User user =  null;
        try
        {
            session = HibernateUtil.openSession();
            tx = session.beginTransaction();
            user = (User)session.load(User.class, 1);
            tx.commit();
        }
        catch (Exception e)
        {
            e.printStackTrace();
            tx.rollback();
        }
        finally
        {
            HibernateUtil.close(session);
        }
        return user;
    }
}
复制代码
复制代码
  @Test
    public void testLazy06()
    {
        UserDAO userDAO = new UserDAO();
        User user = userDAO.loadUser(2);
        System.out.println(user);
    }
复制代码

模拟了一个UserDAO这样的对象,然后我们在测试用例里面来通过load加载一个对象,此时我们发现控制台会报LazyInitializationException异常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session  .............

这个异常是什么原因呢??还是因为load的延迟加载机制,当我们通过load()方法来加载一个对象时,此时并没有发出sql语句去从数据库中查询出该对象,当前这个对象仅仅是一个只有id的代理对象,我们还并没有使用该对象,但是此时我们的session已经关闭了,所以当我们在测试用例中使用该对象时就会报LazyInitializationException这个异常了。

所以以后我们只要看到控制台报LazyInitializationException这种异常,就知道是使用了load的方式延迟加载一个对象了,解决这个的方法有两种,一种是将load改成get的方式来得到该对象,另一种是在表示层来开启我们的session和关闭session。


13

Hibernate中createCriteria即QBC查询的详细用法


现在假设有一个Student类,内有id,name,age属性
String hql = "from Student s";
按照以前的做法,我们通常是
Query query = session.createQuery(hql);
或者要按照条件检索的话.
String hql = "from Student s where s.name like '王%'"
Query query = session.createQuery(hql);
不用HQL而使用QBC的话,那么代码为:
Criteria criteria =session.createCriteria(Student. class);
Criterion criterion = Expression.like( "name", "王%");
这样还看不出来.那我们把检索条件加上年龄为22.
HQL:
String hql = "from Student s where s.name like '王%' and s.age= 22 ";
Query query = session.createQuery(hql);
List list = query.list();
QBC:
Criteria criteria =session.createCriteria(Student. class);
Criterion criterion1 = Expression.like( "name", "王%");
Criterion criterion2 = Expression.eq( "age",newInteger(22));
criteria.add(criterion1).add(criterion2);
List list = criteria.list();


看上去烦琐很多.但是做过项目的人都知道,当一个模块业务逻辑发生改变的时候,往往要重写sql,最烦也是最讨厌的就是拿着别人的hql或者sql,两眼瞪的溜园找到底要修改什么地方呢?
如果使用QBC大大的增加了代码的可读性,以及可维护性.
需要注意的是 null
比如我们要查找姓名为 null的Student对象时应该这么写
Criteria criteria =session.createCriteria(Student. class);
Criterion criterion = Expression.isNull( "name");
criteria.add(criterion).list();
以及使用between...and的时候
Criteria criteria =session.createCriteria(Student. class);
Criterion criterion1 = Expression.ge( "age", new Integer(20)); //下限
Criterion criterion2 = Expression.le( "age", new Integer(25)); //上限
//这里也可以把上述两个条件添加到第三个条件里
Criterion criterion3 =Expression.and(criterion1,criterion2);
criteria.add(criterion3).list();
相当于from Student s where s.age between 20 and 25
等同于from Student s where s.age >= 20 and s.age <=25


下面是就HQL和QBC常用的查询条件做的比较
表达式含义                                     HQL                                     QBC
大于等于                                         >=                                        Expression.ge()
大于                                                 >                                         Expression.gt()
小于等于                                         <=                                        Expression.le()
小于                                                 <                                         Expression.lt()
等于                                                 =                                         Expression.eq()
不等于                                             <>或者!=                            Expression.ne()    

为空                                                 is null                             Expression.isNull()
不为空                                             is notnull                        Expression.isNotNull()
在指定范围内                                 betweenand                        Expression.between()
不在指定范围                                 not betweenand                Expression.not(Expression.between())
属于某个集合                                 in                                        Expression.in()
不属于某个集合                             notin                                 Expression.not(Expression.in())
与                                                    and                                     Expression.and()
或                                                    or                                        Expression.or()
非                                                    not                                     Expression.not()
模糊查询                                        like                                    Expression.like











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值