OpenSessionInViewFilter在web.xml中的配置

3/8/2017来源:ASP.NET技巧人气:1170

1.如果使用HibernateTemplate,默认session在使用后会关闭,如果使用load延迟加载获得PRoxy对象后,就无法在前台获取数据。

2.OpenSessionInViewFilter的作用是延长hibernate中Session的生命周期到页面,使用Proxy时获取数据。

3.使用OpenSessionInViewFilter只需在web.xml中作为一个Filter进行配置,OpenSessionInViewFilter的位置必须在Struts2过滤器前,否则无用

4.使用OpenSessionInViewFilter后,Session的flush mode默认设为manual,此时持久化对象可能会抛异常,因为HibernateTemplate会检查flush mode

protected void checkWriteOperationAllowed(Session session) throws InvalidDataaccessApiUsageException {   if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&     session.getFlushMode().lessThan(FlushMode.COMMIT)) {    throw new InvalidDataAccessApiUsageException(      "Write operations are not allowed in read-only mode (FlushMode.MANUAL): "+      "Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");   }  }

如果小于COMMIT级别,就会抛异常

5.解决的方法是自定义一个继承OpenSessionInViewFitler的类,如用名为OpenSessionInViewFilter,重写getFlushMode方法,返回AUTO或者COMMIT

@Override  protected FlushMode getFlushMode() {      return FlushMode.AUTO;  }

6.此操作并不能保证Session的dml操作成功,因为HibernateTemplate的并不主动提交事务commit,只有FlushMode变化(不是Hibernate中的FlushMode)或者无Transaction时才会flush

protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {   if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {    logger.debug("Eagerly flushing Hibernate session");    session.flush();   }  }

而一般情况会靠Transaction去处理flush

7.对于6的解决方法,就是让Transaction存在,比如配置TransactionManager

在配置 Structs, Spring 和Hibernate整合的问题:

开启OpenSessionInViewFilter来阻止延迟加载的错误的时候抛出了这个异常:

    org.springframework.dao.InvalidDataAccessApiUsageException错误 但是在我们开启OpenSessionInViewFilter这个过滤器的时候FlushMode就已经被默认设置为了MANUAL!

如果FlushMode是MANUAL或NEVEL,在操作过程中 hibernate会将事务设置为readonly,所以在增加、删除或修改操作过程中会出现如下错误:

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

解决办法1:

    直接修改OpenSessionInViewFilter过滤器的配置,配置过滤器的时候配置就是在一般的配置里面加上下面蓝色部分就可以了,直接指定flushMode的配置就OK了:

下面是配置文件:(web.xml)

复制代码
<filter>     <filter-name>OpenSessionInViewFilter</filter-name>      <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>       <init-param>            <param-name>flushMode</param-name>            <param-value>AUTO</param-value>        </init-param></filter><filter-mapping>     <filter-name>OpenSessionInViewFilter</filter-name>     <url-pattern>/*</url-pattern></filter-mapping>
复制代码

解决方法2:

    就是配置事务的边界,在你方法的执行时配置事务边界!

下面是sessionFactor.xml配置:

复制代码
<!-- 事务的配置 -->    <!-- sessionFactory 为自己配置 sessionFactory 的 bean-->    <bean id="txManager"        class="org.springframework.orm.hibernate3.HibernateTransactionManager">        <property name="sessionFactory" ref="sessionFactory" />    </bean>       <aop:config>         <!-- execution(public * *.*.*..*.*(..)) 为自己项目中操作数据库中的方法 -->        <aop:pointcut id="**" expression="execution(public * *.*.*..*.*(..))" />        <aop:advisor pointcut-ref="**"            advice-ref="txAdvice" />    </aop:config>    <tx:advice id="txAdvice" transaction-manager="txManager">        <tx:attributes>             <!-- name 为 方法名 -->            <tx:method name="**" read-only="true" />            <tx:method name="**" propagation="REQUIRED"/>        </tx:attributes>    </tx:advice>
复制代码

下面是总结:

原理:因为配置openSessionInView时,启动后他默认是给没有配置事务边界的方法都默认为只读的,所以在插入数据时就会报上面的错