hibernate的延迟问题
环境strut1.x+spring+hibernate
Hibernate允许对关联对象、属性进行延迟加载,但是必须保证延迟加载的操作限于同一个 Hibernate Session 范围之内进行。如果 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当Web 层访问到那些需要延迟加载的数据时,由于加载领域对象的 Hibernate Session 已经关闭,这些导致延迟加载数据的访问异常。
而Spring为我们提供的OpenSessionInViewFilter过滤器为我们很好的解决了这个问题。OpenSessionInViewFilter是Spring提供的一个针对Hibernate的一个支持类,其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。
由于Hibernate引入了Lazy Load特性,使得脱离Hibernate的Session周期的对象如果再想通过getter方法取到其关联对象的值,Hibernate会抛出一个LazyLoad的Exception。所以为了解决这个问题,Spring引入了这个Filter,使得Hibernate的Session的生命周期变长。
有两种方式可以配置实现OpenSessionInView,分别是OpenSessionInViewInterceptor和OpenSessionInViewFilter,功能完全相同,只不过一个在web.xml配置,另一个在application.xml配置。
但是,使用SSH架构的项目很有可能都遇到过openSessionInView失效问题原因是因为加载spring配置文件都是通过spring的struts插件来实现,即在struts的配置文件中通过ContextLoaderPlugIn在加载spring的上下文配置文件:
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml,
/WEB-INF/action-servlet.xml"/>
</plug-in>
通过上面的org.springframework.web.struts.ContextLoaderPlugIn作为struts的plugin来加载spring的配置文件,会绕过openSessionInView,从而使得openSessionInView失效。
因此,使用org.springframework.web.context.ContextLoaderListener来加载spring的配置文件。
解决方法:
首先:将在struts配置文件中的加载spring的配置文件(下面的代码)删掉。
<plug-in
className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml,
/WEB-INF/action-servlet.xml"/>
</plug-in>
其次:在web.xml文件中加入:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml,classpath*:applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>hibernateFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
<init-param>
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>hibernateFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
即可。
PS:
openSessionInView就是把session关闭延迟到view渲染以后,结合延迟加载产生作用,如果不使用延迟加载也就没有必要使用openSessionInView了。
如果使用Struts,那么需要在Struts的配置文件struts-config.xml里面配置一个Spring的plugin:ContextLoaderPlugIn。实际上ContextLoaderListener和ContextLoaderPlugIn的功能是重叠的,他们都是进行Spring配置的初 始化工作的。因此,如果你不打算使用OpenSessionInView,那么你并不需要在web.xml里面配置 ContextLoaderListener。 如果需要OpenSessionInView模式,由于ContextLoaderListener和ContextLoaderPlugIn功能重叠,都是初始化Spring,你不应该进行两次初始化,所以你不应该同时使用这两者,为了使得OpenSessionInView起作用,应该使用ContextLoaderListener。
spring 有三种启用模式:
1.ContextLoaderServlet
2.ContextLoaderListener
3.ContextLoaderPlugIn
参考:http://www.javaeye.com/topic/73332
http://fusu.com.cn/post/24.html
http://www.javaeye.com/topic/15057
http://blog.csdn.net/dongyansheng_max/archive/2009/07/29/4390978.aspx
http://www.cnblogs.com/cxccbv/archive/2009/07/22/1528825.html