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> 

這樣也能夠解決這個問題

相關文章
相關標籤/搜索