今天客戶提出一個新問題,出庫一批商品,提示失敗了,但是庫存數量卻減少了。看了一下代碼一頭霧水,我們的代碼加了事物,且捕獲異常。
經過調試代碼發現就是兩個原因導致的
第一、在當前方法的catch中處理了捕獲的異常,沒有向上拋出異常,事務不能回滾
分析:
1.在Java中異常的基類為Throwable,他有兩個子類Exception與Errors,同時RuntimeException就是Exception的子類;
2.RuntimeException,即運行時異常,為非受檢(UNCHECKED)異常;
3.Exception的其他子類異常,為非運行時異常,為受檢異常(CHECKED)異常;
Spring事務回滾機制是這樣的:當所攔截的方法有指定異常拋出,事務才會自動進行回滾!
①被攔截方法-—— 注解式:方法或者方法所在類被@Transactional注解;
②異常—— 該方法的執行過程必須出現異常,這樣事務管理器才能被觸發,並對此做出處理;
③指定異常—— 默認配置下,事務只會對Error與RuntimeException及其子類這些UNChecked異常,做出回滾。一般的Exception這些Checked異常不會發生回滾(如果一般Exception想回滾要做出配置);
Spring的聲明式事務是基於AOP的
spring aop 異常捕獲原理:被攔截的方法需顯式拋出異常,並不能經任何處理(如果自己捕獲就不能被聲明式事務感知),這樣aop代理才能捕獲到方法的異常,才能進行回滾,默認情況下aop只捕獲runtimeexception的異常,但可以通過 。
配置來捕獲特定的異常並回滾
換句話說在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),這樣程序異常時才能被aop捕獲進而回滾
解決方案:
方案1.方法中不做異常捕獲,或者在catch語句中最后增加throw new RuntimeException()語句,以便讓aop捕獲異常再去回滾,並且在上層(webservice客戶端,view層action)要繼續捕獲這個異常並處理
方案2.在方法的catch語句中增加:TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();語句,手動回滾,這樣上層就無需去處理異常
第二、在catch中異常拋出Exception,並不是RuntimeException,導致也沒有回滾
解決方法:
① 拋出Exception,同時在事務聲明中加上@Transactional(rollbackFor = Exception.class)
② 在catch添加語句
catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();//就是這一句了,加上之后如果異常后會回滾的 }