Spring 框架透過 Propagation 列舉定義了七種事務傳播行為,掌握它們是正確配置事務邊界的基礎:
前六種對應 EJB CMT 規格,而 PROPAGATION_NESTED 是 Spring 獨有的進階特性,依賴底層事務管理器支援 JDBC 3.0 Savepoint API(如 DataSourceTransactionManager)。
許多開發者誤以為 ServiceA 調用 ServiceB 時,內層方法必須設為 NESTED。實際上,若兩者均配置 REQUIRED,內層方法會自然加入外層事務。若內層拋出異常且外層未特別配置不回滾該異常(如 +MyCheckedException),整個事務仍會回滾。「Service 只能呼叫 DAO」的說法純屬無稽之談,Spring 僅攔截配置了事務屬性的方法,不關心其所在層級。
Juergen Hoeller(Spring 核心開發者)曾詳細闡述兩者本質區別:
關鍵在於異常處理策略:
// ServiceA 修改為捕獲內層異常,執行替代邏輯
void methodA() {
try {
ServiceB.methodB(); // 配置 PROPAGATION_NESTED
} catch (SomeException e) {
// 內層已回滾至 Savepoint,此處可執行 ServiceC.methodC() 等補償操作
ServiceC.methodC();
}
}
若不捕獲異常,異常向上傳播至外部事務邊界,由外部事務的回滾規則決定是否回滾整個事務。
nestedTransactionAllowed 設為 true(預設為 false)。java.sql.Savepoint)。Connection.getMetaData().supportsSavepoints() 必須返回 true(即支援 JDBC 3.0)。底層實現在 AbstractPlatformTransactionManager.handleExistingTransaction 中:檢測到 PROPAGATION_NESTED 時,若允許巢狀事務且使用 Savepoint 機制,則建立 DefaultTransactionStatus 並呼叫 createAndHoldSavepoint(),最終委託 JdbcTransactionObjectSupport 透過 JDBC 3.0 API 建立 Savepoint。