運用@Transactional,本身拋出異常時不會回滾的緣由

    1、 當你讀這篇文章的時候,假如讀者是在整合j2EE的三大框架式遇到這個問題,那應該就是下面這個問題:html

   

    我記得當時我遇到這個問題的時候,是由於數據庫的表,不支持事務!若是mysql不支持存儲引擎,它將以MyISAM表建立表,這是非事務性表。通常修改爲InnoDB.mysql

 

    假若有興趣瞭解 mysql中 " engine=innodb " 以及 " engine=innodb 和engine=myisam的區別 ",能夠讀讀這篇文章,或許對讀者有幫助:http://blog.sina.com.cn/s/blog_6ac4c6cb01018pb1.htmlspring

 

    可以使用下述語句之一檢查表的標類型: 
sql

    SHOW TABLE STATUS LIKE 'tbl_name';
    SHOW CREATE TABLE tbl_name;
數據庫

  使用下述語句,可檢查mysqld服務器支持的存儲引擎: 
   api

    SHOW ENGINES;
 服務器

    也可使用下述語句,檢查與你感興趣的存儲引擎有關的變量值: 

    SHOW VARIABLES LIKE 'have_%';

  例如,要想肯定InnoDB存儲引擎是否可用,可檢查have_innodb變量的值。框架

 

 

 二 、假如讀者不是上述狀況,那請研讀下面這段:測試

--------------------------------------------------------------------------------------------------編碼

 

近日測試用例,發現這樣一個現象:


在業務代碼中,有以下兩種狀況,好比:
throw new RuntimeException("xxxxxxxxxxxx"); 事務回滾
throw new Exception("xxxxxxxxxxxx"); 事務沒有回滾

 

自覺得很瞭解事務,或許時間久遠的緣故,沒分析出來何故,遂查閱了下資料,寫下了以下的內容,供參考:

 

1).Spring的AOP即聲明式事務管理默認是針對unchecked exception回滾。也就是默認對RuntimeException()異常或是其子類進行事務回滾;checked異常,即Exception可try{}捕獲的不會回滾,若是使用try-catch捕獲拋出的unchecked異常後沒有在catch塊中採用頁面硬編碼的方式使用spring api對事務作顯式的回滾,則事務不會回滾, 「將異常捕獲,而且在catch塊中不對事務作顯式提交=生吞掉異常」 ,要想捕獲非運行時異常則須要以下配置:

解決辦法:
1.在針對事務的類中拋出RuntimeException異常,而不是拋出Exception。
2.在txAdive中增長rollback-for,裏面寫本身的exception,例如本身寫的exception:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
   <tx:attributes>
     <tx:method name="*" rollback-for="com.cn.untils.exception.XyzException"/>
   </tx:attributes>
 </tx:advice>
 
或者
定義不會滾的異常


<tx:advice id="txAdvice">
    <tx:attributes>
       <tx:method name="update*" no-rollback-for="IOException"/>
       <tx:method name="*"/>
    </tx:attributes>
 </tx:advice>

 

想讓Exception回滾的話:

<tx:advice id="txAdvice">
    <tx:attributes>
       <tx:method name="*" propagation="REQUIRED" rollback-for="Exception"/>
    </tx:attributes>
 </tx:advice>


2).spring的事務邊界是在調用業務方法以前開始的,業務方法執行完畢以後來執行commit or rollback(Spring默認取決因而否拋出runtime異常).
 若是拋出runtime exception 並在你的業務方法中沒有catch到的話,事務會回滾。 
 通常不須要在業務方法中catch異常,若是非要catch,在作完你想作的工做後(好比關閉文件等)必定要拋出runtime exception,不然spring會將你的操做commit,這樣就會產生髒數據.因此你的catch代碼是多此一舉。
 
如:
try {  
    //bisiness logic code  
} catch(Exception e) {  
    //handle the exception  
}  

 由此能夠推知,在spring中若是某個業務方法被一個 整個包裹起來,則這個業務方法也就等於脫離了spring事務的管理,由於沒有任何異常會從業務方法中拋出!全被捕獲併吞掉,致使spring異常拋出觸發事務回滾策略失效。
 不過,若是在catch代碼塊中採用頁面硬編碼的方式使用spring api對事務作顯式的回滾,這樣寫也何嘗不可。
 
 3).基於註解的事務:

 Transactional的異常控制,默認是Check Exception 不回滾,unCheck Exception回滾 若是配置了rollbackFor 和 noRollbackFor 且兩個都是用一樣的異常,那麼遇到該異常,仍是回滾 rollbackFor 和noRollbackFor 配置也許不會含蓋全部異常,對於遺漏的按照Check Exception 不回滾,unCheck Exception回滾

相關文章
相關標籤/搜索