Hibernate学习笔记整理(七)-----Hibernate检索策略(类级别,关联级别)详解
一、概述
检索策略分三大块,类级别检索策略和关联级别检测策略。
类级别检索策略:get、load、
关联级别检索策略:order.getCustomer().getName()
上面这两种应该是看得懂的。很容易去理解,现在就具体来说说这两种其中的细节。
批量检索解决n+1问题。
二、类级别检索策略
2.1、立即检索 get
直接发送sql语句,到数据库中去查询数据。
Staff staff = (Staff)session.get(Staff.class, 3);//执行完这句,就会发送sql语句,到数据库表中查询相应的数据加入一级缓存中 //结果 Hibernate: select staff0_.id as id1_0_, staff0_.name as name1_0_, staff0_.deptId as deptId1_0_ from staff staff0_ where staff0_.id=?
2.2、延迟检索 load
不会直接发送sql语句,而是等到用的时候在发送sql语句,如果一直没用,就永远不会发送sql语句。
Staff staff = (Staff)session.load(Staff.class, 3);//执行完这句,不会发送sql语句 System.out.println("load后还没发送sql语句,等用到的时候才会发送。"); System.out.println(staff.getName());//现在需要用staff。则会发送sql语句。 //结果 load后还没发送sql语句,等用到的时候才会发送。 Hibernate: select staff0_.id as id1_0_, staff0_.name as name1_0_, staff0_.deptId as deptId1_0_ from staff staff0_ where staff0_.id=? qqq2
2.3、深入讲解get和load
上面两个只是简单讲解一下立即加载和延迟加载两个概念。现在来讲点深入的东西。
1、load检索返回的代理对象,而不是一个pojo对象,get返回的是pojo对象,这个的前提是一级缓存中没有我们要查询的对象。

2、get和load都是先从一级缓存中拿数据,而不是每次都从数据库中拿,也就是说如果一级缓存有我们需要的数据,就不会在发送sql语句了。并且返回就是一级缓存对象中对象的状态,也就是说如果在一级缓存中该对象的状态是pojo对象,那么就算是用load加载的,返回的也就是pojo对象,如果该对象是代理对象,那么就算get加载的,返回的也就是代理对象,不过会将代理对象的数据初始化。也就是会向数据库中发送sql语句查询数据。 解释:代理对象数据初始化:代理对象中包含了我们想要的pojo对象的所有信息。
例子:一级缓存中的是代理对象,使用get获得
Staff staff = (Staff)session.load(Staff.class, 3);//staff代理对象加入缓存中了 System.out.println("没有发送sql语句,get之后就会发送。"); Staff staff1 = (Staff)session.get(Staff.class, 3);//get获取了缓存中的代理对象,并且初始化 //结果 没有发送sql语句,get之后就会发送。 Hibernate: select staff0_.id as id1_0_, staff0_.name as name1_0_, staff0_.deptId as deptId1_0_ from staff staff0_ where staff0_.id=?

例子: 一级缓存中是pojo对象,通过load获得
Staff staff = (Staff)session.get(Staff.class, 3);//staff pojo对象加入缓存中了 System.out.println("get后发送sql语句,并且该pojo对象在一级缓存中了。"); Staff staff1 = (Staff)session.load(Staff.class, 3);//load获取了缓存中的pojo对象 //结果 Hibernate: select staff0_.id as id1_0_, staff0_.name as name1_0_, staff0_.deptId as deptId1_0_ from staff staff0_ where staff0_.id=? get后发送sql语句,并且该pojo对象在一级缓存中了。

3、只有在使用时,代理对象才会初始化,其实还有一种方式可以不使用代理对象而初始化数据,

因为没有初始化代理对象,在关闭session后,在使用staff1,就会报错,报错内容为不能够初始化代码对象,没有session

使用Hibernate.initialize(proxy);来对代理对象进行初始化,这个的效果和使用代理对象是一样的,但是会使代码看起来更好,如果你在这里system.out.println(代理对象),也有也可以,但是看起来总觉得乖乖的,所以hibernate就有了这个方法来对代理对象进行初始化。
4、可以通过lazy属性来设置让load不延迟加载,而跟get一样立即加载,因为是类级别检索,所以在hbm映射文件中的class位置进行属性设置。

在staff.hbm.xml中设置了lazy=false。意思是让其延迟加载失效,所以在对staff进行查询时,使用load也是立即检索

5、我们常说的,get如果查询数据库中没有的记录的话,返回是null,而load将会报错。这句话是正确的,但是概念很模糊,来看下面的路子看会不会报错。
例子一:查询数据库中没有的数据,id=100,load的时候会不会报错? 不报错

例子二:查询数据库中没有的数据,id=100,并且将其取出id 不报错

例子三:查询数据库中没有的数据,id=100,并且取出name 报错

总结load:load加载返回的是一个代理对象,并且我们说的用load查询一个数据库中没有的数据,并不是load这条语句报异常,而是在使用时,代理对象在数据库表中找不到数据而报的异常,所以单纯只写load语句,是不会报错的,并且代理对象的id是我们手动输入进去的,不用往数据库中查也知道,所以在代理对象.getId()时也不会发送sql语句,而是拿到我们一开始的id值。
2.4、load和get的区别(面试题)
1、get是立即加载、load是延迟加载
2、get和load都是先从缓存中查找对象,如果有该对象的缓存,则不向数据库中查询,并且返回的是缓存中对象的状态(是代理对象就返回代理对象,是pojo对象就返回pojo对象)
3、在缓存中没有对象时,get返回的是pojo对象,load返回的是代理对象
三、关联级别检索策略
关联对象属性的抓取策略(关联的表的字段)
fetch=FetchType.EAGER立即抓取(显式)
fetch=FetchType.LAZY延迟抓取(默认)
Hibernate为了性能默认关联对象属性LAZY延迟抓取(推荐),然后在Dao层根据需要使用左外连接,内连接加上fetch关键字实现关联数据的抓取(填充)。
Query query = session.createQuery("from Company c left join fetch c.flights where c.companyName like ?");
flights 为Company 对象的集合属性。查询结束后得到Company 关联的flights 集合数据填充到Company 对象。
浙公网安备 33010602011771号