spring事務之傳播性

朽年發表於2019-03-25

一、事務傳播性

什麼是事務的傳播性 事務的傳播性一般在事務巢狀時候使用,比如在事務A裡面呼叫了另外一個使用事務的方法,那麼這倆個事務是各自作為獨立的事務執行提交,還是內層的事務合併到外層的事務一塊提交那,這就是事務傳播性要確定的問題。下面一一介紹比較常用的事務傳播性。

1.1 PROPAGATION_REQUIRED(同一個事務)

Spring預設的事務傳播機制,如果外層有事務則當前事務加入到外層事務,一塊提交一塊回滾,如果外層沒有事務則當前開啟一個新事務。這個機制可以滿足大多數業務場景。 示例:

public class ServiceA {
    @Autowired
    private ServiceB serviceB;
    public void testA(){
        serviceB.testB();
    }
}
public class ServiceB {
    public voic testB(){
        ......
    }
}
複製程式碼

ServiceA 和ServiceB都是進行過事務增強後的,那麼在執行testA的時候會開啟一個事務,執行到testB()時候由於傳播性是PROPAGATION_REQUIRED,所以testB方法加入到testA的事務(同一個事務裡),那麼testB和testA就會同時提交,同時回滾。值得注意的是如果testA裡面呼叫testB時候加了trycatch沒有把異常跑出去,而testB方法卻丟擲了異常,那麼整個事務也會回滾,這時候呼叫testA的外層會受到"Transaction rolled back because it has been marked as rollback-only的異常,而把testB真正的異常吃掉了。平時我們service層不應該catch掉異常,而應該丟擲來,讓呼叫方catch異常。

1.2 PROPAGATION_REQUIRES_NEW(兩個不同的事務)

該傳播機制是每次新開啟一個事務,同時把外層的事務掛起,當前新事務執行完畢後在恢復上層事務的執行。 以上面程式碼為例,首先進入testA方法前會開啟一個事務,然後呼叫testB時候會把testA的事務掛起,從新開啟一個新事務執行testB,執行完畢後恢復testA的事務。如果testB丟擲來異常則testB的事務會回滾,那麼testA方法是否回滾?這個要看情況,如果test在呼叫sayHello 時候使用了trycatch並且異常沒有在catch中throw出來,那麼testA方法不會回滾,這時候testB是提交和回滾對testA沒有影響,。 如果testA中沒有加trycatch那麼,testA也會回滾。

1.3 PROPAGATION_SUPPORTS(可有可無)

該傳播機制如果外層有事務則加入該事務,如果不存在也不會建立新事務,直接使用非事務方式執行。 以上面程式碼為例,由於PROPAGATION_SUPPORTS,所以testA和testB都沒有開啟事務,沒啥好講的。 如果testA傳播性是PROPAGATION_REQUIRED,testB傳播性是PROPAGATION_SUPPORTS的情況。這時候外層testA會開啟一個事務,然後testB執行時候會加入到test的事務和1.1類似,(也是同一個事務)同時提交同時回滾。

1.4 PROPAGATION_NOT_SUPPORTED(不支援事務)

該傳播機制不支援事務,如果外層存在事務則掛起外層事務 ,然後執行當前邏輯,執行完畢後,恢復外層事務。 同樣這裡看下如果testA使用PROPAGATION_REQUIRED,testB傳播性是PROPAGATION_NOT_SUPPORTED的情況,首先testA會開啟一個事務,然後testB執行時候會掛起該事務然後在非事務內做自己的事情,做完後在恢復testA的事務。 無論testB是否丟擲異常,testB的事務都不會回滾,因為它不在事務範圍內,那testA就和1.2一樣了,如果test catch住sayHello的異常沒有throw出去,那麼test就不回滾,否者回滾。

1.5 PROPAGATION_NEVER

該傳播機制不支援事務,如果外層存在事務則直接丟擲異常。 IllegalTransactionStateException( "Existing transaction found for transaction marked with propagation 'never'")

1.6 PROPAGATION_MANDATORY

該傳播機制是說配置了該傳播性的方法只能在已經存在事務的方法中被呼叫,如果在不存在事務的方法中被呼叫,會丟擲異常。(呼叫者必須是事務,否則報錯) IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'");

1.7 PROPAGATION_NESTED

它是已經存在事務的一個真正的子事務. 潛套事務開始執行時, 它將取得一個 savepoint. 如果這個巢狀事務失敗, 我們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務結束後它才會被提交或回滾. 也就是外部事務提交子事務才能commit,外部事務回滾子事務也回滾 如果內部事務回滾將不影響外部事務,內部事務回滾時只回滾到savepoint,當然內部事務可以通過回滾手動丟擲異常影響外部事務(業務需求而定)。 其用法和1.1的PROPAGATION_REQUIRED幾乎一樣,最大的不同是此情景下如果testA呼叫testB時trycatch了,而testB拋異常了,testA是不會回滾和拋異常的。

總結,只有傳播性為PROPAGATION_REQUIRED||PROPAGATION_REQUIRES_NEW||PROPAGATION_NESTED時候才可能開啟一個新事務。

相關文章