聲明式事務的傳播機制是解決多個事務方法嵌套調用時,事務如何創建、復用、掛起或隔離的核心邏輯。它的實現依賴于事務管理器、事務狀態管理、線程上下文綁定等組件的協同,本質是通過一套 “規則判斷 + 狀態維護” 的邏輯,在方法調用時動態決定事務的行為。
一、傳播機制的核心目標
當一個帶有@Transactional
的方法 A 調用另一個帶有@Transactional
的方法 B 時,需要解決:
- 方法 B 是否復用方法 A 的事務?
- 方法 B 是否需要新建事務,同時掛起方法 A 的事務?
- 如果方法 A 沒有事務,方法 B 是否必須報錯(如 MANDATORY)?
傳播機制就是通過預定義的規則(如 REQUIRED、REQUIRES_NEW 等),自動處理這些場景,避免手動控制事務的繁瑣。
二、實現的核心組件
傳播機制的實現依賴于 Spring 事務體系中的幾個核心組件,它們的協作是關鍵:
TransactionDefinition
定義了事務的 “元信息”,包括:- 傳播行為(propagationBehavior):如 REQUIRED、REQUIRES_NEW 等;
- 隔離級別、超時時間、是否只讀等。
每個@Transactional
注解的方法都會被解析為一個TransactionDefinition
對象,作為傳播機制的判斷依據。
PlatformTransactionManager
事務管理器的頂層接口,其中getTransaction(TransactionDefinition definition)
方法是傳播機制的 “決策核心”—— 它根據當前線程的事務狀態和TransactionDefinition
中的傳播行為,決定如何處理事務(創建、復用、掛起等)。TransactionStatus
維護事務的實時狀態,包括:- 是否是新創建的事務(isNewTransaction ());
- 是否掛起了外層事務(如果有);
- 事務是否被標記為回滾(isRollbackOnly ())。
它是事務管理器和后續操作(提交 / 回滾)的 “狀態憑證”。
TransactionSynchronizationManager
通過ThreadLocal
存儲當前線程的事務上下文(如當前事務的連接、掛起的事務等),讓事務管理器能感知到 “當前線程是否已有事務”。TransactionInterceptor(AOP 攔截器)
作為 AOP 的環繞通知,在目標方法執行前觸發事務管理器的getTransaction()
方法(決策傳播行為),在方法執行后根據結果觸發commit()
或rollback()
。
三、傳播機制的實現流程
以 “方法 A 調用方法 B” 為例,拆解傳播機制的核心步驟:
步驟 1:AOP 攔截與元信息解析
當方法 B 被調用時,TransactionInterceptor
先攔截調用,解析方法 B 上@Transactional
注解的屬性(如傳播行為、隔離級別),生成TransactionDefinition
對象。
步驟 2:判斷當前線程是否已有事務
事務管理器通過TransactionSynchronizationManager
的hasResource(...)
方法,檢查當前線程的ThreadLocal
中是否綁定了事務資源(如數據庫連接)。
- 如果有資源,說明當前線程已有事務(可能是方法 A 創建的);
- 如果沒有,說明當前線程無事務。
步驟 3:根據傳播行為決策事務操作
事務管理器的getTransaction()
方法根據 “當前是否有事務” 和 “傳播行為”,執行不同邏輯:
傳播行為 | 決策邏輯(核心) |
---|---|
REQUIRED | 若當前有事務,復用當前事務(返回已有的 TransactionStatus);若沒有,新建事務。 |
REQUIRES_NEW | 無論當前是否有事務,都新建一個事務;若有當前事務,先掛起(存入 ThreadLocal)。 |
SUPPORTS | 若當前有事務,復用;若沒有,以非事務方式執行(不創建事務)。 |
MANDATORY | 若當前有事務,復用;若沒有,直接拋出異常(要求必須在事務中執行)。 |
步驟 4:維護事務狀態(TransactionStatus)
- 對于新建的事務:
TransactionStatus
會標記isNewTransaction()=true
,并將事務資源(如數據庫連接)通過TransactionSynchronizationManager
綁定到當前線程。 - 對于復用的事務:
TransactionStatus
會關聯到外層事務的狀態,同時記錄 “嵌套層級”(方便后續提交 / 回滾時判斷是否是最外層事務)。 - 對于掛起的事務(如 REQUIRES_NEW):會將當前事務的狀態存入
ThreadLocal
的 “掛起隊列”,待新事務完成后恢復。
步驟 5:事務執行與后續處理
方法 B 執行完成后,TransactionInterceptor
會根據執行結果(正常 / 異常)和TransactionStatus
決定提交或回滾:
- 若方法 B 是新建事務(如 REQUIRES_NEW 或 REQUIRED 且無外層事務):直接提交或回滾,并解綁線程資源;
- 若方法 B 是復用外層事務(如 REQUIRED 且有外層事務):僅標記事務狀態(如異常時標記
rollbackOnly
),最終由最外層事務統一提交 / 回滾; - 若方法 B掛起了外層事務(如 REQUIRES_NEW):提交 / 回滾新事務后,從
ThreadLocal
中恢復被掛起的外層事務,繼續執行外層邏輯。
四、關鍵細節:嵌套事務的狀態管理
傳播機制的核心難點是 “嵌套事務的狀態同步”,例如:
- 當內層方法(REQUIRED)拋出異常時,會將外層事務的
TransactionStatus
標記為rollbackOnly
,外層方法執行到最后會發現這個標記,從而觸發整體回滾; - 當內層方法使用 REQUIRES_NEW 時,它的事務獨立于外層,內層提交 / 回滾不會影響外層(但外層可以捕獲內層異常后繼續執行)。
這一切都依賴TransactionStatus
對狀態的精準記錄,以及TransactionSynchronizationManager
對線程上下文的維護 —— 確保事務狀態在嵌套調用中不混亂。
總結
聲明式事務傳播機制的實現,本質是:
通過 AOP 攔截事務方法,解析傳播規則,結合線程本地存儲(ThreadLocal)感知當前事務狀態,由事務管理器動態決策事務的創建、復用或掛起,并通過事務狀態(TransactionStatus)維護嵌套關系,最終實現多個事務方法嵌套時的自動化事務管理。
理解傳播機制的關鍵,在于把握 “當前線程事務狀態” 與 “傳播行為規則” 的對應關系,以及TransactionStatus
如何串聯起整個事務的生命周期。
如果這篇文章對大家有幫助可以點贊關注,你的支持就是我的動力😊!