论坛首页 Java企业应用论坛

延迟加载时为什么不自动open session呢?

浏览 8967 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-03-13  
    用了hibernate都有差不多2年时间,一直都没有深入研究,最近学习起它的延迟加载。
    在网上找了很多资料,它们都是说,使用延迟加载时,被加载对象(也就是那个proxy)必须是同一个session打开的前提下,才能获取数据,否则,会抛出session is closed 或 disconnection session 异常。
    对此,我有个疑问,为什么hibernate在检测到与proxy相关联的session 是close或disconnection 时,不自动open,反而是抛异常。可能是为了事务的一致性考虑。
    了解这个问题的目的是要找出一种方法替代opensessioninview,我认为,延迟加载可以用于2个场景中,一个是从数据库取出数据,并传递到view层展现;另一个是在后台处理的时候。若是第一种场景的话,我觉得proxy取数据时,自己打开session并以只读方法加载数据,并不需要用opensessioninview的长连接。至于后一种在后台处理时,大可以把所需要的数据预先取出,而不需要使用延迟加载。
    希望各位发表一下意见。
   发表时间:2008-03-13  
事情没你想像的那么简单。Hibernate通过Session的一级缓存来管理持久化对象的状态,当Session关闭之后,持久化对象究竟处于何种状态是未知的,此时如果自动打开第2个Session,这个Session的缓存里面没有这个持久化对象的引用关系,因此无法判断对象状态,那么就很有可能带来一些不可预知的后果,比方说应该update的时候却没有update,应该级联插入却没有插入等等。

1 请登录后投票
   发表时间:2008-03-13  
好像可以配一个拦截器,当关闭时自动打开(spring中)
0 请登录后投票
   发表时间:2008-03-13  
我也有个疑问。sessin关闭之后应该只与数据库断开连接,数据还保存在session中,且此session与用户关联!
ps:
hibernate的源码太复杂了,根本看不懂
1 请登录后投票
   发表时间:2008-03-14  
robbin说的的确有道理,2个session处理同一个对象时,很容易会出现不可预料的结果。但是,请想一下延迟加载的使用场景,一般是在后台查询数据然后在前台部分显示,在这种情况下,打开的第二个session只是用于数据的加载,并不会对相关数据进行增删改操作。与此同时,我认为session的生存期是比较短的,如在opensessioninview的模式中,session会在请求结束时close掉,并且会被回收,所以当我打开第二个session加载数据,完毕后关闭,不使用第二个session执行增删改操作,理论上是不会出现这种不可预知的后果。
因此,我观点是在view层展示数据的时候,session reconnect或者新开一个session去取lazy数据,这种方法是可取的。不知robbin有何看法。
8 请登录后投票
   发表时间:2008-03-14  
hibernate里应该不能2个session里处理同一个对象的,这里的对象是指session维护的java对象,一个对象只能被一个session处理,但多个session可以处理数据库中同一条记录,session close后只是清除缓存(快照并非里面的对象),只要有引用指着原有对象,该对象不会释放,再重连后我觉得还是同一个session,lz你用了延迟加载,取数据时当然会去查数据库。另外你可以试试,先查一个对象放入httpsession中,再在另一个请求中save这个对象,就会报错,具体报什么我忘了。以上是我的理解,不知正不正确。
0 请登录后投票
   发表时间:2008-03-14  
huangjiej 写道
robbin说的的确有道理,2个session处理同一个对象时,很容易会出现不可预料的结果。但是,请想一下延迟加载的使用场景,一般是在后台查询数据然后在前台部分显示,在这种情况下,打开的第二个session只是用于数据的加载,并不会对相关数据进行增删改操作。与此同时,我认为session的生存期是比较短的,如在opensessioninview的模式中,session会在请求结束时close掉,并且会被回收,所以当我打开第二个session加载数据,完毕后关闭,不使用第二个session执行增删改操作,理论上是不会出现这种不可预知的后果。
因此,我观点是在view层展示数据的时候,session reconnect或者新开一个session去取lazy数据,这种方法是可取的。不知robbin有何看法。


session reconnect是完全可以的,但问题是你还是要持有session,否则你从哪来reconnect?既然你要一直持有session,那就还是OpenSessionInView模式,没啥本质区别,唯一的区别只在于底层的数据库连接是否被分配而已。

如果关闭session再次打开,即使是只读,也一定会报错。这是因为lazy的对象引用关系是关联到当前的session上的,你关闭掉session以后,打开一个新的session,这个新的session和你内存当中的lazy对象没有任何引用关系,所以当你存取lazy对象的时候,lazy对象找不到引用的session,就会报错。


0 请登录后投票
   发表时间:2008-03-14  
哦,那proxy其实是有绑定session的
我稍稍看一下源码,hibrenate的延迟加载代理对象分成
PersistentCollection 集合类的延迟加载,在其抽象实现类(AbstractPersistentCollection)里,保存了SessionImplementor(保存session与其它hibernate对象的关联,实际上session也继承此接口),只不过是私有变量。
HibernateProxy(好像是代理实体类的),有方法 getHibernateLazyInitializer()取出LazyInitializer,在LazyInitializer身上,我们也能看到SessionImplementor,所以要取出session还是有可能的,只不过,这就带有一定的bad smell,呵呵。
恰巧,我也找到一份这样的代码,其思想是在hibernate抛出session close异常时,会创建一个session并查询数据,(http://www.360works.com/articles/detail/56/),“Hibernate Lazy Loading patch” ,它是基于hibernate2的,直接是修改了hibernate里面的代码.
0 请登录后投票
   发表时间:2008-03-14  
to hrtc:

   "再重连后我觉得还是同一个session",是的,重连是同一个session的,可看我上面回复的内容。
   至于“另外你可以试试,先查一个对象放入httpsession中,再在另一个请求中save这个对象,就会报错,具体报什么我忘了” ,这个要分2个情况考虑哦,一种是没有使用lazy的或者lazy的属性的值都已经取出来的,这个应该是没有问题的。另一种是使用了lazy,而且这个对象中的lazy属性没有加载数据,这个很大可能会出问题,因为这时是2个session同时操作一个对象。
    我没有试过,抽空测试一把把结果告诉大家。
  
0 请登录后投票
   发表时间:2008-04-01  
最近,我也碰到了这个问题,感觉延迟加载就像鸡肋,我的客户端是基于Eclipse的rpc的,通过webservice来调用的,很难实现opensessioninview,我只能lazy=“false”来解决了,不知大家对于webservice这样东西,用Hibernate有什么好的建议
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics