spring MVC中 Write operations are not allowed in read-only mode (FlushMode.MANUAL)解决办法

            Hibernate 容许对关联对象、属性进行延迟加载,可是必须保证延迟加载的操做限于同一个 Hibernate Session 范围以内进行。若是 Service 层返回一个启用了延迟加载功能的领域对象给 Web 层,当 Web 层访问到那些须要延迟加载的数据时,因为加载领域对象的 Hibernate Session 已经关闭,这些致使延迟加载数据的访问异常。而Spring为咱们提供的OpenSessionInViewFilter过滤器为咱们很好的解决了这个问 题。OpenSessionInViewFilter的主要功能是使每一个请求过程绑定一个 Hibernate Session,即便最初的事务已经完成了,也能够在 Web 层进行延迟加载的操做。OpenSessionInViewFilter 过滤器将 Hibernate Session 绑定到请求线程中,它将自动被 Spring 的事务管理器探测到。web

            看过OpenSessionInViewFilter之后就知道,OpenSessionInViewFilter的getSession方法中会对session的flushMode设定一个默认为NEVER的值。spring

我在用STRUCT2的时候只要在web.xml中配上下面的配置就能够了,不过我发现我在Spring MVC中这样配发现并无起做用。
express

<filter>
        <filter-name>openSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate4.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>session

这时候解决办法有两个:
1:继承OpenSessionInViewFilter,并覆盖getSession,设施flushMode 为AUTO
2:经过spring的事务管理Hibernate的sessionFactory,对不一样的数据操做做事务的隔离及限制

由于反正都要用到spring做事务管理,因此我在项目中采用了第二种方法,而后我在spring的配置文件中这样配mvc

<bean id="txManager"
        class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <aop:config>
        <aop:pointcut id="bussinessService"
            expression="execution(* com.pyp.workflow.dao.impl.*.*(..))" />
        <aop:advisor pointcut-ref="bussinessService" advice-ref="txAdvice" />
    </aop:config>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <tx:attributes>
            <tx:method name="get*" read-only="false" propagation="NOT_SUPPORTED" />
            <tx:method name="find*" propagation="NOT_SUPPORTED" />
            <tx:method name="save*" propagation="REQUIRED" />
            <tx:method name="update*" propagation="REQUIRED" />
            <tx:method name="delete*" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>app

    而后配完以后并无用,事务没有生产。这就挺奇怪了的,我搞了很久才查到ide

    你们先看下面配置,spring中自动扫包的url

    <context:component-scan base-package="com">
spa

            看过spring的参考手册的朋友都会这样配置,由于省事,一句话能够自动把com包低下的全部带annotation注解的类都实例化并配好了。因此习惯的也在springMVC中也做了这样的配置。hibernate

但若是这样简单的配置会致使刚才spring的事务配置失效缘由:
        实例化@Controller类时,Spring会自动把关联的@Service(此@Service已作了@Transaction事务注解)类实例化,此时事务并未生效,致使@Transaction注解无效,事务未被注册,所以须要把@Controller和其它的@Service,@Components,@Reposity等分开实例化,在事务生效后,而且其它组件都实例化完成后,@Controller最后实例化。因此在SpringMVC的配置文件中

<context:component-scan base-package="com.*.*.*">

这个配置要配到Controller(对应struct2中的action)这一层的根目录下。这样就能够解决这个问题。


还有一种解决办法就是在spring中的配置文件中这样配

<!-- 扫描com及子包,自动实例化带@注释的实例,这里排除@Controller,全部controller的实例化在 mvc-config中完成 -->  

<context:component-scan base-package="com">   

   <context:exclude filter type="annotation" expression="org.springframework.stereotype.Controller"/>   

</context:component-scan>


在spring mvc的配置文件这样配

<!-- 扫描com及子包,自动实例化带@controller注释的实例,  

  因为实例化controller时会对controller关联的Service类一同实例化,因此这里须要排除@Service   

-->  

<context:component-scan base-package="com">  

 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>  

<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>  </context:component-scan> 

这样也能够解决这个问题

相关文章
相关标签/搜索