1. 程式人生 > >SpringMVC+MyBatis配置宣告式事務的問題

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>

修改配置後再測試,事務成功回滾。