天天看點

SpringMVC+MyBatis配置聲明式事務的問題

網絡上關于Spring聲明式事務的部落格一堆一堆地,原本不用自己再記筆記,但我最近在用SpringMVC+MyBatis時遇到了事務問題;深知自己水準不高,忘東西又快,是以一解決問題還是第一時間記下來,以備後用。

我的環境是Spring、SpringMVC、MyBatis3、MariaDB和Tomcat

我遇到的問題是事務不起作用,雖然多次資料庫操作中有異常出現,但還是部分送出,并沒有復原;

我的配置是這樣的:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>
  
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
        <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
        <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
        <tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />
        <tx:method name="*" propagation="REQUIRED" read-only="true"/>
    </tx:attributes>
</tx:advice>
<aop:config>
    <aop:pointcut id="pc" expression="execution(* com.xss.*.*.service.impl.*.*(..))" />
    <aop:advisor pointcut-ref="pc" advice-ref="txAdvice" />
</aop:config>
           

這段配置應該是沒有問題的,于是我就想會不會是MariaDB的存儲引擎不支援事務,于是從網上找到了這麼一段話:

MariaDB預設的存儲引擎是Maria,不是MyISAM。Maria可以支援事務,但是預設情況下沒有打開事務支援,因為事務支援對性能會有影響。 可以通過以下語句,轉換為支援事務的Maria引擎:

ALTER TABLE ‘tablename’ ENGINE=MARIA TRANSACTIONAL=1;

但我按照上面所述修改了資料庫的存儲引擎,事務仍然不起作用。

注:在MariaDB(MySQL)資料中,InnoDB和BerkeleyDB兩種存儲引擎是支援事務的,MariaDB引進的新引擎Aria預設不支援事務,可以通過上面的代碼修改。

糾結了許久終于發現還是自己的配置出了問題,但并非是事務配置有問題,而是Spring元件掃描配置出了問題。

由于采用的是SpringMVC、 MyBatis,故統一采用了@Service、@Controller注解來聲明Service和Controller 元件,于是我在Spring和SpringMVC的配置檔案均用一行代碼配置了Spring的元件自動掃描:

<context:component-scan base-package="com.xss.crm" />
           

而由于伺服器啟動時的加載Spring相關配置檔案的順序為applicationContext.xml(Spring的配置檔案) ---> applicationContext-mvc.xml(SpringMVC的配置檔案),按照上面的配置Spring加載applicationContext.xml配置檔案時會加載@Controller注解标注的Controller元件,并且對其進行掃描裝配,但是此時的Service還沒有進行事務增強處理,得到的将是原樣的Service(沒有經過事務加強處理,故而沒有事務處理能力),是以我們應用在applicationContext.xml(Spring配置檔案)中不掃描Controller,而在applicationContext-mvc.xml(SpringMVC配置檔案)中不掃描Service。

于是Spring和SpringMVC配置應該像下面的這樣:

applicationContext.xml(Spring配置檔案)

<!-- 自動掃描元件,這裡不掃描 controller,它們是在ApplicationContext-mvc.xml中配置掃描的,如果不去除會影響事務管理   -->
<context:component-scan base-package="com.xss.crm">
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
           

applicationContext-mvc.xml(SpringMVC配置檔案)

<!-- 掃描所有的controller 但是不掃描service-->
<context:component-scan base-package="com.xss.crm">
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
</context:component-scan>
           

修改配置後再測試,事務成功復原。

參考部落格:http://sence-qi.iteye.com/blog/1328902/