關於Spring 事務管理傳播屬性的配置及作用-嵌套事務


先了解事務的7種傳播屬性:

PROPAGATION_REQUIRED -- 支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。 
PROPAGATION_SUPPORTS -- 支持當前事務,如果當前沒有事務,就以非事務方式執行。 
PROPAGATION_MANDATORY -- 支持當前事務,如果當前沒有事務,就拋出異常。 
PROPAGATION_REQUIRES_NEW -- 新建事務,如果當前存在事務,把當前事務掛起。 
PROPAGATION_NOT_SUPPORTED -- 以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。 
PROPAGATION_NEVER -- 以非事務方式執行,如果當前存在事務,則拋出異常。 
PROPAGATION_NESTED -- 如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。 
前六個策略類似於EJB CMT,第七個(PROPAGATION_NESTED)是Spring所提供的一個特殊變量。 
它要求事務管理器或者使用JDBC 3.0 Savepoint API提供嵌套事務行為(如Spring的DataSourceTransactionManager)

 

問題產生場景:

 1.在 DemoServiceA.java中有方法 demoMethodA().其中嵌套DemoServiceB.java中demoMethodB()。當demoMethodA事務發生rollback時, demoMethodB 事務也可以rollback或是commit。

如圖:

public class DemoServiceA {
    
    public void demoMethodA() {
        
        demoServiceB.demoMethodB();//Insert對象B 操作
} }

 

常見解決方案: 

public class DemoServiceA {
    
    /** 
     * 新建事務
     * 事務屬性配置為 PROPAGATION_REQUIRED 
     */  
    @Transactional(propagation=Propagation.REQUIRED)
    public void demoMethodA() {
        //操作...
        
        /** 
         * 1.事務屬性配置為 PROPAGATION_REQUIRES_NEW ;
         * A. DemoServiceA 事務commit與rollback,與 DemoServiceB無任何關系,DemoServiceB 不屬於事務 DemoServiceA的子事務。
         *    PROPAGATION_REQUIRES_NEW 啟動一個新的, 不依賴於環境的 "內部" 事務. 這個事務將被完全 commited 
         *    或 rolled back 而不依賴於外部事務, 它擁有自己的隔離范圍, 自己的鎖, 當內部事務開始執行時, 
         *    外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行. 
         * B. 可以起到分支執行的效果。service方法雖然嵌套但是事務之間狀態相互無影響
         *  
         *  
         *     
         * 2.事務屬性配置為 PROPAGATION_NESTED;
         * PROPAGATION_NESTED 開始一個 "嵌套的" 事務,  它是已經存在事務的一個真正的子事務. 
         * 潛套事務開始執行時,  它將取得一個 savepoint. 如果這個嵌套事務失敗, 
         * 我們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束后它才會被提交. 
         * 
         */   
        demoServiceB.demoMethodB();//Insert對象B 操作
        //操作...
        
    }
}

 

下面詳細介紹7種事務傳播屬性在示例中的作用:

1: REQUIRED

加入當前正要執行的事務不在另外一個事務里,那么就起一個新的事務

比如說,DemoServiceB.demoMethodB的事務級別定義為REQUIRED, 那么由於執行DemoServiceA.demoMethodA的時候,

DemoServiceA.demoMethodA已經起了事務,這時調用DemoServiceB.demoMethodB,DemoServiceB.demoMethodB看到自己已經運行在DemoServiceA.demoMethodA

的事務內部,就不再起新的事務。而假如DemoServiceA.demoMethodA運行的時候發現自己沒有在事務中,他就會為自己分配一個事務。

這樣,在DemoServiceA.demoMethodA或者在DemoServiceB.demoMethodB內的任何地方出現異常,事務都會被回滾。即使DemoServiceB.demoMethodB的事務已經被

提交,但是DemoServiceA.demoMethodA在接下來fail要回滾,DemoServiceB.demoMethodB也要回滾

2: SUPPORTS

如果當前在事務中,即以事務的形式運行,如果當前不再一個事務中,那么就以非事務的形式運行

3: MANDATORY

必須在一個事務中運行。也就是說,他只能被一個父事務調用。否則,他就要拋出異常

4: REQUIRES_NEW

這個就比較繞口了。 比如我們設計DemoServiceA.demoMethodA的事務級別為REQUIRED,DemoServiceB.demoMethodB的事務級別為REQUIRES_NEW,

那么當執行到DemoServiceB.demoMethodB的時候,DemoServiceA.demoMethodA所在的事務就會掛起,DemoServiceB.demoMethodB會起一個新的事務,等待DemoServiceB.demoMethodB的事務完成以后,

他才繼續執行。他與REQUIRED 的事務區別在於事務的回滾程度了。因為DemoServiceB.demoMethodB是新起一個事務,那么就是存在

兩個不同的事務。如果DemoServiceB.demoMethodB已經提交,那么DemoServiceA.demoMethodA失敗回滾,DemoServiceB.demoMethodB是不會回滾的。如果DemoServiceB.demoMethodB失敗回滾,

如果他拋出的異常被DemoServiceA.demoMethodA捕獲,DemoServiceA.demoMethodA事務仍然可能提交。

5: NOT_SUPPORTED

當前不支持事務。比如DemoServiceA.demoMethodA的事務級別是REQUIRED ,而DemoServiceB.demoMethodB的事務級別是NOT_SUPPORTED ,

那么當執行到DemoServiceB.demoMethodB時,DemoServiceA.demoMethodA的事務掛起,而他以非事務的狀態運行完,再繼續DemoServiceA.demoMethodA的事務。

6: NEVER

不能在事務中運行。假設DemoServiceA.demoMethodA的事務級別是REQUIRED, 而DemoServiceB.demoMethodB的事務級別是NEVER ,

那么DemoServiceB.demoMethodB就要拋出異常了。

7: NESTED

理解Nested的關鍵是savepoint。他與REQUIRES_NEW的區別是,REQUIRES_NEW另起一個事務,將會與他的父事務相互獨立,

而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最后回滾,他也要回滾的。

 


免責聲明!

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



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