在项目中时常会碰见对关联表数据的操作。例如用户与角色表、角色与资源表等等,在建立这些表对应得实体时,默认采用的懒加载机制(fetch=FetchType.LAZY)及只有在需要的时候才会查询对应得关联表数据。但是在spring管理的hibernate一次请求的session默认在Service层有效。离开Service层当前请求的session就关闭了。若我们想在jsp页面得到关联表对应的数据就会报no session错。
为了实现这一需求主要两种方案:
1、在建立关联实体对象时关闭懒加载功能。及设置fetch=FetchType.EAGER
2、需要在web.xml中配置OpenSessionInViewFilter过滤器。
Spring 为我们提供了一个叫做 OpenSessionInViewFilter 的过滤器,他是标准的 Servlet Filter 所以我们把它按照规范配置到 web.xml 中方可使用。使用中我们必须配合使用 Spring 的 HibernateDaoSupport 来进行开发,也就是说,我们的dao层的类都要继承于 HibernateDaoSupport,从中由 Spring 来控制 Hibernate 的 Session 在请求来的时候开启,走的时候关闭,保证了我们访问数据对象时的稳定性。
<!-- 配置OpenSessionInViewFilter 保证session在一次请求完成后才关闭 -->
<filter>
<filter-name>openSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
<init-param>
<!-- singleSession默认为true,若设为false则等于没用OpenSessionInView 。所以默认可以不写 -->
<param-name>singleSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<!--
指定org.springframework.orm.hibernate3.LocalSessionFactoryBean在spring配置文件中的名称,默认值为sessionFactory。
如果LocalSessionFactoryBean在spring中的名称不是sessionFactory,该参数一定要指定,否则会出现找不到sessionFactory的例外。所以默认可以不写
-->
<param-name>sessionFactoryBeanName</param-name>
<param-value>sessionFactory</param-value>
</init-param>
<init-param>
<!--
在项目中使用Spring+Hibernate的时候,会开启OpenSessionInViewFilter来阻止延迟加载的错误,
但是在我们开启OpenSessionInViewFilter这个过滤器的时候FlushMode就已经被默认设置为了MANUAL,如果FlushMode是MANUAL或NEVEL,
在操作过程中 hibernate会将事务设置为readonly,若要进行增加、删除或修改操作则需要手动设置flushMode为AUTO
-->
<param-name>flushMode</param-name>
<param-value>AUTO</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>openSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
OpenSessionInViewFilter的主要功能是用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态,使session在request的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭session。
由于使用了OpenSessionInView模式后造成了内存和数据库连接问题
这个问题是我在生产环境中碰到的一个问题。由于使用了OpenSessionInView模式,Session的生命周期变得非常长。虽然解决了Lazy Load的问题,但是带来的问题就是Hibernate的一级缓存,也就是Session级别的缓存的生命周期会变得非常长,那么如果你在你的Service层做大批量的数据操作时,其实这些数据会在缓存中保留一份,这是非常耗费内存的。还有一个数据库连接的问题,存在的原因在于由于数据库的Connection是和Session绑在一起的,所以,Connection也会得不到及时的释放。因而当系统出现业务非常繁忙,而计算量又非常大的时候,往往数据连接池的连接数会不够。这个问题我至今非常头痛,因为有很多客户对数据连接池的数量会有限制,不会给你无限制的增加下去。
http://www.cnblogs.com/children/archive/2010/05/01/1725419.html
OpenSessionInViewFilter作用及配置:http://www.yybean.com/opensessioninviewfilter-role-and-configuration;
OpenSessionInView详解:http://www.javaeye.com/topic/32001
http://schnauzer.iteye.com/blog/160024