受困于hibernate的openSessionInViewFilter

08-10-14 freeren
今天突然发现项目中用了这个东东,又现在做的东东需要延迟加载,由于怎么看这个都不算是个好东东:
1、这个本身是Spring的产物,看看他的原理:
request-->open session-->打开连接、开始事务-->持久操作-->渲染(关闭连接、session)-->response
其中一些过程省略了,不是很关心。
2、看到这个就怀疑了:这样lazy load怎么用?session都闭了,那lazy load从何而来?不是得重新再关联到一个新的session?

请老师和各位道友帮忙解答,谢谢!

banq
2008-10-15 10:32
>这样lazy load怎么用?session都闭了,那lazy load从何而来?不是得重新再关联到一个新的session?

Session关闭是在response阶段,也就是http获得返回数据的最后关头才关闭,所以session相当于request scope的长连接,相当于你把jdbc连接在每一次请求request时都一直打开着,直至结果返回浏览器那最后一瞬间关闭。

这无疑是危险的,我们一直强点JDBC连接即用即关,否则,一旦程序出错,内存泄漏相当严重,Hibernate创始人也谈了这个问题,在他的Seam框架中有好的解释。

有些外行人经常将Spring+Hibernate看成黄金组合,实际是跟在老外后面瞎起哄,误导了大批项目和系统。

看看OSIV这个标签中其他更多的讨论。

[该贴被banq于2008-10-15 10:33修改过]

freeren
2008-10-15 23:02
首先谢谢老师的回答,可能之前理解有些偏差,以为是在session.flush()时才打开连接,现在想想应该是在之前,也就是请求之后马上就打开了--在filter里打开的吧,这样的话这个连接的确是挺长的,也就是说这个连接的生命周期约等于信赖的session的生命周期了。
其次想来谈谈这个session级别的缓存,也就是hibernate自带的第一级缓存。不知道老师对于这一级缓存的用法有什么建议?我是这么理解的,当我们新持久化一个新的实体对象时,这时调用了session.save(),但目前还没有和DB同步,当我们flush()后才同步到DB的,这时的缓存中应该还有一份最样的对象。而如果我们做的是一次检索对象,这时这个session是一个新的,那么其缓存也是空的吧?那这个load()又有什么用呢?还不是要到DB去查找呢?

banq
2008-10-16 12:57
》个session级别的缓存,也就是Hibernate自带的第一级缓存

这个session不是http请求的session,实际是一个请求scope内的缓存,如果客户端重新发出请求,那么Hibernate就开始新的session,从数据库中获得,所以一级缓存只是对一个请求命令中一系列处理有作用,而对多次请求的applcation级别则无效,这时要使用二级缓存了,而且是只读操作,所以就不需要事务,可以自己随意配置指定,hibernate没有缺省封装,hibernate缺省封装的一级缓存有事务的,是缓存+事务。

freeren
2008-10-16 23:08
>>hibernate缺省封装的一级缓存有事务的,是缓存+事务
这样可以理解这个级别的缓存还是信赖于数据库吗?还有感觉这个load()与get()在实际使用中并没有差别,因为在一次请求范围内,load()来自这个缓存中并无对象,所以还是要到DB再检索一次才有对象的。load()说与get()区别是前者在这个缓存检索,get()则是直接到DB中检索,还有就是返回不一样,其他的有差别吗?感觉这个缓存作用不是很大。

xmuzyu
2008-10-23 15:45
>>load()说与get()区别是前者在这个缓存检索,get()则是直接到DB中检索,还有就是返回不一样,其他的有差别吗?

load其实也没有在缓存中查找,其实load是生产了一个代理对象,这个代理对象是原来对象的子类,这样hibernate可以拦截方法调用,当访问对象属性的时候才去真正的查询数据库。而get是直接查询数据库,不生产代理对象。所以load在设置关联的时候非常要用。其中JPA中的getReference和find方法和hibernate的load,get方法的作用是一样的。

Hibernate里一级缓存其实就是persistence context,只有你在一个事务中处理时,一级缓存才起作用。至于OSIV,这个还是和事务有关系。我们一般把事务范围界定在service方法调用前后,当service方法调用后,事务结束了,hibernate 的session就关闭了,所以就要用OSIV将事务边界从service方法扩展到requst的周期。

xmuzyu
2008-10-23 15:46
>>load()说与get()区别是前者在这个缓存检索,get()则是直接到DB中检索,还有就是返回不一样,其他的有差别吗?

load其实也没有在缓存中查找,其实load是生产了一个代理对象,这个代理对象是原来对象的子类,这样hibernate可以拦截方法调用,当访问对象属性的时候才去真正的查询数据库。而get是直接查询数据库,不生产代理对象。所以load在设置关联的时候非常要用。其中JPA中的getReference和find方法和hibernate的load,get方法的作用是一样的。

Hibernate里一级缓存其实就是persistence context,只有你在一个事务中处理时,一级缓存才起作用。至于OSIV,这个还是和事务有关系。我们一般把事务范围界定在service方法调用前后,当service方法调用后,事务结束了,hibernate 的session就关闭了,所以就要用OSIV将事务边界从service方法扩展到requst的周期。