精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-03-13
在网上找了很多资料,它们都是说,使用延迟加载时,被加载对象(也就是那个proxy)必须是同一个session打开的前提下,才能获取数据,否则,会抛出session is closed 或 disconnection session 异常。 对此,我有个疑问,为什么hibernate在检测到与proxy相关联的session 是close或disconnection 时,不自动open,反而是抛异常。可能是为了事务的一致性考虑。 了解这个问题的目的是要找出一种方法替代opensessioninview,我认为,延迟加载可以用于2个场景中,一个是从数据库取出数据,并传递到view层展现;另一个是在后台处理的时候。若是第一种场景的话,我觉得proxy取数据时,自己打开session并以只读方法加载数据,并不需要用opensessioninview的长连接。至于后一种在后台处理时,大可以把所需要的数据预先取出,而不需要使用延迟加载。 希望各位发表一下意见。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-03-13
事情没你想像的那么简单。Hibernate通过Session的一级缓存来管理持久化对象的状态,当Session关闭之后,持久化对象究竟处于何种状态是未知的,此时如果自动打开第2个Session,这个Session的缓存里面没有这个持久化对象的引用关系,因此无法判断对象状态,那么就很有可能带来一些不可预知的后果,比方说应该update的时候却没有update,应该级联插入却没有插入等等。
|
|
返回顶楼 | |
发表时间:2008-03-13
好像可以配一个拦截器,当关闭时自动打开(spring中)
|
|
返回顶楼 | |
发表时间:2008-03-13
我也有个疑问。sessin关闭之后应该只与数据库断开连接,数据还保存在session中,且此session与用户关联!
ps: hibernate的源码太复杂了,根本看不懂 |
|
返回顶楼 | |
发表时间:2008-03-14
robbin说的的确有道理,2个session处理同一个对象时,很容易会出现不可预料的结果。但是,请想一下延迟加载的使用场景,一般是在后台查询数据然后在前台部分显示,在这种情况下,打开的第二个session只是用于数据的加载,并不会对相关数据进行增删改操作。与此同时,我认为session的生存期是比较短的,如在opensessioninview的模式中,session会在请求结束时close掉,并且会被回收,所以当我打开第二个session加载数据,完毕后关闭,不使用第二个session执行增删改操作,理论上是不会出现这种不可预知的后果。
因此,我观点是在view层展示数据的时候,session reconnect或者新开一个session去取lazy数据,这种方法是可取的。不知robbin有何看法。 |
|
返回顶楼 | |
发表时间:2008-03-14
hibernate里应该不能2个session里处理同一个对象的,这里的对象是指session维护的java对象,一个对象只能被一个session处理,但多个session可以处理数据库中同一条记录,session close后只是清除缓存(快照并非里面的对象),只要有引用指着原有对象,该对象不会释放,再重连后我觉得还是同一个session,lz你用了延迟加载,取数据时当然会去查数据库。另外你可以试试,先查一个对象放入httpsession中,再在另一个请求中save这个对象,就会报错,具体报什么我忘了。以上是我的理解,不知正不正确。
|
|
返回顶楼 | |
发表时间: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,就会报错。 |
|
返回顶楼 | |
发表时间: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里面的代码. |
|
返回顶楼 | |
发表时间:2008-03-14
to hrtc:
"再重连后我觉得还是同一个session",是的,重连是同一个session的,可看我上面回复的内容。 至于“另外你可以试试,先查一个对象放入httpsession中,再在另一个请求中save这个对象,就会报错,具体报什么我忘了” ,这个要分2个情况考虑哦,一种是没有使用lazy的或者lazy的属性的值都已经取出来的,这个应该是没有问题的。另一种是使用了lazy,而且这个对象中的lazy属性没有加载数据,这个很大可能会出问题,因为这时是2个session同时操作一个对象。 我没有试过,抽空测试一把把结果告诉大家。 |
|
返回顶楼 | |
发表时间:2008-04-01
最近,我也碰到了这个问题,感觉延迟加载就像鸡肋,我的客户端是基于Eclipse的rpc的,通过webservice来调用的,很难实现opensessioninview,我只能lazy=“false”来解决了,不知大家对于webservice这样东西,用Hibernate有什么好的建议
|
|
返回顶楼 | |