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。