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

jiangyaning 2010-06-04

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

拿一对多关系来说明:

在一对多关联关系中,多的一方通过外键来关联一的一方,在查询HQL语句中,要取出多的一方与之相关联的一的一方的OID,非常容易,可在取别的属性时会遇到困难!

例如:多方:学生po字段值id,name,oid

一方:教室po字段值id,name

取出某个学生信息:(HQL)fromStudentstuwherestu.id=?

显示信息:System.out.println("学生姓名:"+user.getName()+"教室ID"+user.getRoom().getOid()+"教室名称"+user.getRoom().getName());

这时将会出错:couldnotinitializeproxy-theowningSessionwasclosed

这是因为,在hibernate机制中默认有延迟加载lazy=”true”也就是说他只取出与只维护关系的oid,别的属性在用到时才会去,据说省内存。可在上边,当关掉session时,他将会变为游离态也就是只有一个id属性了,别的都还没去出来。

解决办法:1.该显示信息在事务关闭之前运行。

2.取消延迟加载,在classroom.Hbm.xml中对象配置文件中直接加入lazy=”false”

3.重新将只有id的对象,通过load()/get()方法变为持久态.

二.get()/load()根本区别

看到许多书谈论这东东感觉还不如自己想想呢:

1)查询id对应的数据时,如果没有找到get()将会返回null,而load()将会发生objectnotfound异常.

2)在延迟加载:get()返回的是一个实际的类实例.而load()方法找到后通过代理对象去延迟加载,当真正用到数据时才会查询数据库,在使用过程中如果出现问题,将会抛异常.

Useruser=(User)session.load(User.class,”1”);A返回实体对象的代理类对象

System.out.println(user.getName());B

注:在执行到A时user因为有延迟加载加载机制,他只得到id属性,在用到别的时在从数据库去查询,,这时在AB中间来一句session.close();那就会抛出couldnotinitializeproxy-theowningSessionwasclosed异常的.

(转载: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*fromuserwhere>

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

Useruser=(User)session.get(User.class,”1”);A

System.out.println(user.getName());B

注:在用get方式时,就可以取出来了,因为他直接得到实列对象而没用延迟加载机制!

这地方选择的时候一定要慎重,是用get()还是load();

3)get方法首先查询session缓存,没有的话查询二级缓存,最后查询数据库;反而load方法创建时首先查询session缓存,没有就创建代理,实际使用数据时才查询二级缓存和数据库。”这是从别的地方听说的

三.对于延迟加载时,用到相关联的类实例时,在session之前可以显示的给予实例化,

Classroomroom=(Classroom)session.load(Classroom.class,1);

if(!Hibernate.isInitialized(room)){

Hibernate.initialize(room);

}

这时就从代理对象类中实例化了该对象.可以在session关闭之后,取出数据.

相关推荐

LetonLIU / 0评论 2020-05-29
东方咖啡屋 / 0评论 2020-01-06