1. 程式人生 > >spring事務在try catch時候的執行

spring事務在try catch時候的執行

spring 的預設事務機制,當出現unchecked異常時候回滾,checked異常的時候不會回滾;

異常中unchecked異常包括error和runtime異常,需要try catch或向上丟擲的異常為checked異常比如IOException,也就是說程式丟擲runtime異常的時候才會進行回滾,其他異常不回滾,可以配置設定所有異常回滾: 

[html] view plain copy  print?在CODE上檢視程式碼片派生到我的程式碼片
  1. @Transactional(rollbackFor = { Exception.class })    
[html] view plain copy  print
?在CODE上檢視程式碼片派生到我的程式碼片
  1. 當有try catch後捕獲了異常,事務不會回滾,如果不得不在service層寫try catch 需要catch後 throw new RuntimeException 讓事務回滾;  

Spring的AOP即宣告式事務管理預設是針對unchecked exception回滾。也就是預設對R untimeException()異常或是其子類進行事務回滾;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>
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回滾

將異常捕獲,並且在catch塊中不對事務做顯式提交(或其他應該做的操作如關閉資源等)=生吞掉異常;

spring的事務邊界是在呼叫業務方法之前開始的,業務方法執行完畢之後來執行commit or rollback(spring預設取決於是否丟擲runtime異常). 
如果丟擲runtime exception 並在你的業務方法中沒有catch到的話,事務會回滾。 
一般不需要在業務方法中catch異常,如果非要catch,在做完你想做的工作後(比如關閉檔案等)一定要丟擲runtime exception,否則spring會將你的操作commit,這樣就會產生髒資料.所以你的catch程式碼是畫蛇添足。

由此可以推知,在spring中如果某個業務方法被一個

     try {   

            //bisiness logic code   

          } catch(Exception e) {   

             //handle the exception   

整個包裹起來,則這個業務方法也就等於脫離了spring事務的管理,因為沒有任何異常會從業務方法中丟擲!全被捕獲併吞掉,導致spring異常丟擲觸發事務回滾策略失效。


不過,如果在catch程式碼塊中採用頁面硬編碼的方式使用spring api對事務做顯式的回滾,這樣寫也未嘗不可。