Hibernate延迟加载-by宋迪

            
1:延迟加载就是延迟到真正需要数据的时候才加载,我第一次理解代理模式就是从这里开始的;
2:Hibernate中提供了对实体对象的延迟加载以及对集合的延迟加载,另外在Hibernate3中还提供了对属性的延迟加载

正文:
一:
1:如果想对实体对象使用延迟加载,必须要在实体的映射配置文件(hbm.xml)中进行相应的配置,如下所示:
<hibernate-mapping>
<class name=”com.neusoft.entity.User” table=”user” lazy=”true”>
通过将class的lazy属性设置为true,来开启实体的延迟加载特性

2:如果我们运行下面的代码:
User user=(User)session.load(User.class,”1”);(1)
System.out.println(user.getName());(2)
当运行到(1)处时,Hibernate并没有发起对数据的查询,如果我们观察此时user对象的内存快照,我们会惊奇的发现,此时返回的可能是User$EnhancerByCGLIB$$bede8986类型的对象,而且其属性为null,
这里所返回的对象实际上只是User对象的代理类对象。在Hibernate中通过使用CGLIB,来实现动态构造一个目标对象的代理类对象,并且在代理类对象中包含目标对象的所有属性和方法,而且所有属性均被赋值为null。
通过调试器显示的内存快照,我们可以看出此时真正的User对象,是包含在代理对象的CGLIB$CALBACK_0.target属性中,当代码运行到(2)处时,此时调用user.getName()方法,这时通过CGLIB赋予的回调机制,实际上调用CGLIB$CALBACK_0.getName()方法,当调用该方法时,Hibernate会首先检查CGLIB$CALBACK_0.target属性是否为null,如果不为空,则调用目标对象的getName方法,如果为空,则会发起数据库查询,生成类似这样的SQL语句:select * from user where id=’1’;来查询数据,并构造目标对象,并且将它赋值到CGLIB$CALBACK_0.target属性中。

3:这样,通过一个中间代理对象,Hibernate实现了实体的延迟加载,

只有当用户真正发起获得实体对象属性的动作时,才真正会发起数据库查询操作。所以实体的延迟加载是用通过中间代理类完成的,所以只有session.load()方法才会利用实体延迟加载,因为只有session.load()方法才会返回实体类的代理类对象。

如果使用get方法,则无论是否开启实体延迟加载机制,都会直接发起sql查询操作(立即加载)


4:在Hibernate的延迟加载机制中,针对集合类型的应用


我们在一对多(或多对多)关联中,定义的用来容纳关联对象的Set集合,并不是java.util.Set类型或其子类型,而是Hibernate自己的Set类型,通过使用自定义集合类的实现,Hibernate实现了集合类型的延迟加载
为了对集合类型使用延迟加载,我们必须在hbm文件中的set部分开启lazy机制,比如:
<set name=”addresses” table=”address” lazy=”true” inverse=”true”>

User user=(User)session.load(User.class,”1”);
Collection addset=user.getAddresses();       (1)
Iterator it=addset.iterator();                (2)
while(it.hasNext()){
Address address=(Address)it.next();
System.out.println(address.getAddress());
当程序执行到(1)处时,这时并不会发起对关联数据的查询来加载关联数据,只有运行到(2)处时,真正的数据读取操作才会开始,这时Hibernate会根据缓存中符合条件的数据索引,来查找符合条件的实体对象。

5:数据索引
在Hibernate中对集合类型进行缓存时,是分两部分进行缓存的,首先缓存集合中所有实体的id列表,然后缓存实体对象,这些实体对象的id列表,就是所谓的数据索引。
当查找数据索引时,如果没有找到对应的数据索引,这时就会一条select SQL的执行,获得符合条件的数据,并构造实体对象集合和数据索引,然后返回实体对象的集合,并且将实体对象和数据索引纳入Hibernate的缓存之中。
另一方面,如果找到对应的数据索引,则从数据索引中取出id列表,然后根据id在缓存中查找对应的实体,如果找到就从缓存中返回,如果没有找到,再发起select SQL查询
6:
在Hibernate3中,引入了一种新的特性——属性的延迟加载。比如,在User对象中有一个resume字段,该字段是一个java.sql.Clob类型,包含了用户的简历信息,当我们加载该对象时,我们不得不每一次都要加载这个字段,而不论我们是否真的需要它,而且这种大数据对象的读取本身会带来很大的性能开销。
在Hibernate3中,我们可以通过属性延迟加载机制,来使我们获得只有当我们真正需要操作这个字段时,才去读取这个字段数据的能力
<class name=”com.neusoft.entity.User” table=”user”>
<property name=”resume” type=”java.sql.Clob” column=”resume” lazy=”true”/>
    </class>
属性延迟加载需要字节码增强器的支持
二:
1:因为有了延迟加载,所以就有了lazyInitializationException,(也就是当你需要加载数据的时候,发现它的session关闭了),一个类从临时态(瞬时态)到持久态,再到游离态是通过是否纳入session管理来区分的,hibernate中的update为什么能更新数据呢,它是将游离的对象重新放回session管理中当然能更新数据了。如果我把持久态对象的数据改变了,是否必须要执行了save方法,这些自己去试一下就知道了,说到这里有点跑偏了,我们还是继续来说lazyInitializationException

2:解决延迟加载异常的方式
保证检索关联属性时,session必须开启
1)全局:把关系映射节点的lazy改为false----关闭延迟加载
2)局部:主动加载
  A:在DAO相应的方法session关闭之前强行使用关联对象,让其主动加载     getxxx()
  B:使用hibernate.initialize()方法,。。
3)DAO方法相互调用时,使用当前session的update方法,将游离态对象跟当前session关联起来
4)OpenSessionInView模式---延长hibernate session开启的时间,延长session关闭时间。把当前session跟当前用户请求绑定在一块。这时session的生命周期就跟一个request一致

方案4) 如图:



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值