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 的事务管理器探测到。

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

我在用STRUCT2的时候只要在web.xml中配上下面的配置就可以了,不过我发现我在Spring MVC中这样配发现并没有起作用。

<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>

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

因为反正都要用到spring作事务管理,所以我在项目中采用了第二种方法,然后我在spring的配置文件中这样配

<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>

    然后配完之后并没有用,事务没有生产。这就挺奇怪了的,我搞了好久才查到

    大家先看下面配置,spring中自动扫包的

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

            看过spring的参考手册的朋友都会这样配置,因为省事,一句话可以自动把com包低下的所有带annotation注解的类都实例化并配好了。所以习惯的也在springMVC中也作了这样的配置。

但如果这样简单的配置会导致刚才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> 

这样也可以解决这个问题






你可能感兴趣的:(spring,过滤器,领域,我们很好)