【注解@Transactional 的事務回滾測試】


通常,在項目中可能看到注解@Transactional(rollbackFor=Exception.class),如果類加了這個注解,那么這個類里面的方法拋出異常,就會回滾,數據庫里面的數據也會回滾(也可以細分顆粒度,到需要事務監控的方法上添加此注解而非類上)。

在@Transactional注解中如果不配置rollbackFor屬性,那么事物只會在遇到RuntimeException的時候才會回滾,加上rollbackFor=Exception.class,可以讓事物在遇到非運行時異常時也回滾

默認spring事務只在發生未被捕獲的 RuntimeExcetpion 時才回滾。也可以說spring會對unchecked異常進行事務回滾;如果是checked異常則不回滾。

一般將派生於Error或者RuntimeException的異常稱為unchecked異常,所有其他的異常成為checked異常。

那么我是不是可以理解為 不加注解,發生空指針而不捕獲時會發生回滾?(下面進行驗證)

 

PS: @Transactional注解 應當應用於service層實現類或實現類中的public方法上,且如果為只讀(查詢)方法無需添加注解。

PSS:着重測試注解屬性:rollbackFor :用於指定能夠觸發事務回滾的異常類型,可以指定多個異常類型,常見的runtime異常:空指針異常,數組越界異常

 

現將進行測試,測試的控制變量如下:

  1.添加注解@Transactional(rollbackFor = Exception.class)

  2.添加注解@Transactional(norollbackFor = Exception.class)

  3.捕獲 runtime 異常

  4.不捕獲 runtime 異常

  

 好了,開測:

  測試用例1:不添加@Transactional注解,測試異常為空指針異常,而捕獲的是runtime異常,結果是 無回滾,無異常拋出,數據順利更新。

   測試用例2:不添加@Transactional注解,測試異常為空指針異常,而捕獲的是數組越界異常,結果是 無回滾,拋出空指針異常,數據可順利更新。

  測試用例3:和測試用例2類似,但沒有使用try-catch去捕獲runtime異常,結果依舊是 沒有回滾。

 

   測試用例4:添加@Transactional(rollbackFor = NullPointerException.class)注解,指定空指針類型異常,測試異常為空指針異常,而捕獲的是數組越界異常,結果是 發生回滾, 數據無更新。

 

    測試用例5:添加@Transactional(rollbackFor = NullPointerException.class)注解,測試異常為空指針異常,而捕獲的是Exception異常(包含空指針異常),結果是 不發生回滾, 數據有更新。

 

 

     測試用例6:添加@Transactional(norollbackFor = NullPointerException.class)注解,測試異常為空指針異常,而捕獲的ArrayIndexOutOfBoundsException

異常(包含空指針異常),結果是 不發生回滾, 數據有更新。

 

 好了,以上列舉了6種情況,總結如下:

  1.當沒有配置注解@Transactional時,spring默認是不開啟事物管理的。

  2.配置注解后,回滾的前提是,try-catch捕獲情況符合注解中參數的規范,且方法用public修飾,要求mysql數據庫的引擎是支持事物的比如InnoDB( 可以用show variables like 'default_storage_engine'語句來查看數據庫當前引擎)

  3.配置注解后,如果catch中捕獲到了對應異常,那么即使配置注解也不會發生回滾。

  3.再次聲明,unchecked exception–編譯器不要求強制處置的異常,可以理解為 java.lang.RuntimeException類及它的子類都是非受查異常,如錯誤的類型轉換異常:ClassCastException,下標越界異常:ArrayIndexOutOfBoundsException,空指針訪問異常:NullPointerException,除零溢出異常:ArithmeticException等;

  4.注解屬性:

 

【關於事務嵌套】

有兩個事務方法,父方法中調用子方法,想實現子方法回滾而父方法不觸發回滾,可以設置如下:

  @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW)
  // 子方法觸發事務時會暫時掛起父事務;

 

 

【關於同一類中非事務方法A調用 事務方法B,事務失效問題】

// 因為 B方法被A調用,而事務需要切面實現,這時對B方法的切入失效,我們需要新建一個代理對象去調用方法B,這樣事務不會失效。(XxxxService為業務類對象)
XxxxxxService self = (XxxxxxxService) AopContext.currentProxy();

 需要依賴:

        <!-- 切點表達式依賴 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
            <scope>runtime</scope>
        </dependency>

 

 

附:

參考博客:https://www.cnblogs.com/clwydjgs/p/9317849.html

spring aop 異常捕獲原理:被攔截的方法需顯式拋出異常,並不能經任何處理,這樣aop代理才能捕獲到方法的異常,才能進行回滾,默認情況下aop只捕獲runtimeexception的異常,但可以通過配置來捕獲特定的異常並回滾。

在Spring FrameWork 的事務框架中推薦的事務回滾方法是,在當前執行的事務上下文中拋出一個異常。如果異常未被處理,當拋出異常調用堆棧的時候,Spring FrameWork 的事務框架代碼將捕獲任何未處理的異常,然后並決定是否將此事務標記為回滾。

在默認配置中,Spring FrameWork 的事務框架代碼只會將出現runtime, unchecked 異常的事務標記為回滾;也就是說事務中拋出的異常時RuntimeException或者是其子類,這樣事務才會回滾(默認情況下Error也會導致事務回滾)。在默認配置的情況下,所有的 checked 異常都不會引起事務回滾。

注:Unchecked Exception包括Error與RuntimeException. RuntimeException的所有子類也都屬於此類。另一類就是checked Exception。

 

Spring的事務管理默認是針對unchecked exception回滾,也就是默認對Error異常和RuntimeException異常以及其子類進行事務回滾,且必須對拋出異常,若使用try-catch對其異常捕獲則不會進行回滾!(Error異常和RuntimeException異常拋出時不需要方法調用throws或try-catch語句);
checked異常,checked異常必須由try-catch語句包含或者由方法throws拋出,且事務默認對checked異常不進行回滾。
在service層若不加@Transactional則spring默認是不開啟事物管理的。

從源碼來看,默認回滾的 類型確實是runtime異常和error

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM