1. 程式人生 > >spring的事務傳播機制

spring的事務傳播機制

前言:

Spring預設情況下會對執行期發生的異常(RunTimeException),即uncheck異常,進行事務回滾。如果遇到checked異常就不回滾。

不過也可以自定義:

1. 讓checked也回滾:在整個方法前加上

@Transactional(rollbackFor=Exception.class)

2 .讓unchecked不回滾:

@Transactional(notRollbackFor=RunTimeException.class)

3 .不需要事務管理的(只查詢)方法:

@Transactional(propagation=Propagation.NOT_SUPPORTED)

正片:

在 spring的 TransactionDefinition介面中一共定義了六種事務傳播屬性:

TransactionDefinition中定義的->

Ⓐ :支援當前事務,如果當前沒有事務

Ⓑ:以非事務方式執行操作,如果當前存在事務

樣式:

甲方法{

       乙方法;

}

Required :Ⓐ, 新建。

注:甲有事務,乙就不再起新的事務。發生異常,一起回滾。

甲無事務,乙就會自己建一個,發生異常,甲回滾,乙不會

Supports :Ⓐ, 非事務。

注:甲有事務,乙不會再起新的事務。發生異常,一起回滾。

甲無事務,乙就以非事務執行,發生異常,也不會回滾。

Mandatory: Ⓐ, 拋異常。

注:甲有事務,乙不會再起新的事務。發生異常,一起回滾。

甲無事務,乙馬上拋異常。

requires_NEW :新建事務,如果當前存在事務,把當前事務掛起。

注:甲有事務,乙會新建事務,將甲的事務掛起。發生異常,只有乙回滾。

當乙事務結束時,甲會繼續有事務。

甲無事務,乙會新建事務。發生異常,只有乙回滾。

例:甲是required,乙是requires_NEW

甲和乙不會因為對方的執行情況而影響事務的結果, 因為它們根本就是兩個事務

但注意一種情況。

如果乙已經提交,

如果乙丟擲的異常未被甲的try-catch捕獲,那麼甲會回滾。

使用場景:一般日誌記錄行為不應影響主邏輯,可以用requires_NEW

日誌服務的事務策略配置為propagation="REQUIRES_NEW",告訴Spring不管上下文是否有事務,Log Service被呼叫時都要求一個完全新的只屬於Log Service自己的事務。通過該事務策略,Log Service可以獨立的記錄日誌資訊,不再受到業務邏輯事務的干擾。

NOT_supported :Ⓑ,掛起。

注:甲有事務,將甲掛起,乙以非事務執行,乙結束後,甲的事務繼續。

甲無事務,乙以非事務執行。

Never :Ⓑ,拋異常。

注:甲只要有事務,就拋異常

甲無事務,乙以非事務執行。

下面的要求事務管理器支援事務巢狀行為。

在 spring 中使用 PROPAGATION_NESTED的前提:

1. 我們要設定 transactionManager 的 nestedTransactionAllowed 屬性為 true, 注意, 此屬性預設為 false!!!

2. java.sql.Savepoint 必須存在, 即 jdk 版本要 1.4+

3. Connection.getMetaData().supportsSavepoints() 必須為 true, 即 jdbc drive 必須支援 JDBC 3.0

Nested :如果當前存在事務,則在巢狀事務內執行。如果當前沒有事務,則進行與Required類似的操作。

例:甲是required,乙是requires_Nested

這時候乙是甲的事務的一部分

如果甲提交,乙也會被提交

如果甲回滾,乙也會被回滾

應用場景:

ServiceA {  

     //事務屬性配置為 PROPAGATION_REQUIRED

    void methodA() {  

        try {  

            ServiceB.methodB();  

        } catch (SomeException) {  

            // 執行其他業務, 如 ServiceC.methodC();  

        }  

    }  

}  

這樣會有分支執行的效果

1.如果 ServiceB.methodB 失敗, 那麼執行 ServiceC.methodC(),

而 ServiceB.methodB 已經回滾到它執行之前的 SavePoint, 所以不會產生髒資料(相當於此方法從未執行過), 這種特性可以用在某些特殊的業務中。

2.當然methodA可以自由決定到底是提交還是回滾。

理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是:

PROPAGATION_REQUIRES_NEW 完全是一個新的事務,它與外部事務相互獨立; 而 PROPAGATION_NESTED 則是外部事務的子事務, 如果外部事務 commit, 巢狀事務也會被 commit, 這個規則同樣適用於 roll back。