web 开发中hibernate 延迟加载解决方法

一.hibernate 延迟加载深入研究:

拿一对多关系来说明:
在一对多关联关系中,多的一方通过外键来关联一的一方,在查询HQL语句中,要取出多的一方与之相关联的一的一方的OID,非常容易,可在取别的属性时会遇到困难!
例如:多方: 学生po 字段值 id ,name ,oid
一方:教室 po 字段值 id ,name
取出某个学生信息:(HQL)from Student stu where stu.id=?
显示信息: System.out.println("学生姓名:"+user.getName()+"教室ID "+user.getRoom().getOid()+"教室名称"+user.getRoom().getName());
这时将会出错:could not initialize proxy - the owning Session was closed
这是因为,在hibernate 机制中默认有延迟加载lazy=”true”也就是说他只取出与只维护关系的oid,别的属性在用到时才会去,据说省内存。可在上边,当关掉 session时,他将会变为游离态也就是只有一个id属性了,别的都还没去出来。
解决办法:1.该显示信息在事务关闭之前运行。
2.取消延迟加载,在classroom.Hbm.xml中对象配置文件中直接加入lazy=”false”
3.重新将只有id 的对象,通过load() /get()方法变为持久态.
二.get() /load()根本区别
看到许多书谈论这东东感觉还不如自己想想呢:
1)查询id 对应的数据时,如果没有找到get()将会返回null,而load() 将会发生object not found异常.
2)在延迟加载 : get()返回的是一个实际的类实例. 而load()方法找到后通过代理对象去延迟加载,当真正用到数据时才会查询数据库,在使用过程中如果出现问题,将会抛异常.
User user=(User)session.load(User.class,”1”); A 返回实体对象的代理类对象
System.out.println(user.getName()); B
注:在执行到A时user因为有延迟加载加载机制,他只得到id属性,在用到别的时在从数据库去查询,,这时在A B中间来一句session.close();那就会抛出could not initialize proxy - the owning Session was closed异常的.
(转载: Hibernate并没有发起对数据的查询,如果我们此时通过一些调试工具(比如JBuilder2005的Debug工具),观察此时user对象的内存快照,我们会惊奇的发现,此时返回的可能是User$EnhancerByCGLIB$$bede8986类型的对象,而且其属性为null,这是怎么回事?还记得前面我曾讲过session.load()方法,会返回实体对象的代理类对象,这里所返回的对象类型就是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 >
这样,通过一个中间代理对象,Hibernate实现了实体的延迟加载,只有当用户真正发起获得实体对象属性的动作时,才真正会发起数据库查询操作。所以实体的延迟加载是用通过中间代理类完成的,所以只有session.load()方法才会利用实体延迟加载,因为只有session.load()方法才会返回实体类的代理类对象。)
User user=(User)session.get(User.class,”1”); A
System.out.println(user.getName()); B
注:在用get方式时,就可以取出来了,因为他直接得到实列对象而没用延迟加载机制!
这地方选择的时候一定要慎重,是用get() 还是 load();

3)get方法首先查询session缓存,没有的话查询二级缓存,最后查询数据库;反而load方法创建时首先查询session缓存,没有就创建代理,实际使用数据时才查询二级缓存和数据库。”这是从别的地方听说的
三. 对于延迟加载时,用到相关联的类实例时,在session之前可以显示的给予实例化,
Classroom room=(Classroom)session.load(Classroom.class, 1);
if(!Hibernate.isInitialized(room)){
Hibernate.initialize(room);
}
这时就从代理对象类中实例化了该对象.可以在session关闭之后,取出数据.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值