首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

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

2012-10-21 
web 开发中hibernate 延迟加载解决方法一.hibernate 延迟加载深入研究:拿一对多关系来说明:在一对多关联关

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关闭之后,取出数据.

热点排行