关于openSessionInView的问题

来源:互联网 发布:美国eia数据在那里看 编辑:程序博客网 时间:2024/06/09 18:56

openSessionInView实现Hibernate的延迟加载功能。其主要意思是在发起一个页面请求时打开Hibernate的Session,一直保持这个Session,直到这个请求结束,具体是通过一个Filter来实现的。

由于Hibernate引入了Lazy Load特性,使得脱离Hibernate的Session周期的对象如果再想通过getter方法取到其关联对象的值,Hibernate会抛出一个LazyLoad的Exception。所以为了解决这个问题,Spring引入了这个Filter,使得Hibernate的Session的生命周期变长。

spring中对OpenSessionInViewFilter的描述如下:
它是一个Servlet2.3过滤器,用来把一个Hibernate Session和一次完整的请求过程对应的线程相绑定。目的是为了实现"Open Session in View"的模式。
例如: 它允许在事务提交之后延迟加载显示所需要的对象。

openSessionInView需要在web.xml中加入如下配置(此监听器应该在struts2的filter前面):

 <filter>    <filter-name>openSessionInView</filter-name>    <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>    </filter>        <filter-mapping>        <filter-name>openSessionInView</filter-name>        <url-pattern>/*</url-pattern>    </filter-mapping>
如果在spring中没有配置事务,在进行增删改时,会抛出

org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

产生原因:

在网上查了查,这个问题的原因原来是这样的

OpenSessionInViewFilter在getSession的时候,会把获取回来的session的flush mode 设为FlushMode.NEVER。然后把该sessionFactory绑定到TransactionSynchronizationManager,使request的整个过程都使用同一个session,在请求过后再接除该sessionFactory的绑定,最后closeSessionIfNecessary根据该session是否已和transaction绑定来决定是否关闭session。在这个过程中,若HibernateTemplate 发现自当前session有不是readOnly的transaction,就会获取到FlushMode.AUTO Session,使方法拥有写权限。
也即是,如果有不是readOnly的transaction就可以由Flush.NEVER转为Flush.AUTO,拥有insert,update,delete操作权限,如果没有transaction,并且没有另外人为地设flush model的话,则doFilter的整个过程都是Flush.NEVER。所以受transaction保护的方法有写权限,没受保护的则没有。

解决方法:

在beans.xml中配置事务,并且配置事务的传播特性,表明对于以create、delete、update开头的所有方法设置默认事务支持

<bean id="transactionManager"class="org.springframework.orm.hibernate3.HibernateTransactionManager"><property name="sessionFactory" ref="sessionFactory" /></bean><!-- 配置事务的传播特性 ,指定事务管理器--> <tx:advice id="txAdvice" transaction-manager="transactionManager">  <!-- 配置详细的事务语义 -->  <tx:attributes>   <tx:method name="create*" propagation="REQUIRED" />   <tx:method name="delete*" propagation="REQUIRED" />   
   <tx:method name="update*" propagation="REQUIRED" />
  <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice>

对于Spring的OpenSessionInViewFilter来说,虽然数据库连接被保持了过长的时间,但是并没有锁定数据库资源,特别是事务资源。因为Spring的事务是通过TransactionInterceptor来实现的,在MVC结构中,当最后一个业务bean被调用结束以后,Transaction就已经被提交了。此后,虽然数据库连接还保持中,但是数据库资源没有锁定问题。数据库连接应该尽早被释放,以缓解数据库资源的压力,延迟很久才释放,会导致需要更多的数据库连接,并发量大的时候经常出现连接池耗尽。Session被延迟很久释放,那么Session占用的一级缓存也会占用比较长时间,这意味着会无谓消耗更多的JVM内存。OpenSessionInView虽然确实方便,但是还是慎用.

对于性能方面看看这个老帖子吧:http://www.iteye.com/topic/17501