首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring 事務傳播行為深度解析與異常處理實戰

     編輯:Java 綜合教學

Spring 事務傳播行為核心概念

在 Spring 框架中,事務傳播行為定義了當一個事務方法被另一個事務方法調用時,事務如何傳播與邊界劃分。TransactionDefinition 介面定義了七種傳播行為常量,掌握它們是處理複雜事務場景的基礎。

七大傳播行為詳解

  • PROPAGATION_REQUIRED(預設):若當前存在事務則加入,否則新建事務。最常用,適合大多數業務場景。
  • PROPAGATION_REQUIRES_NEW:強制創建新事務,若當前存在事務則掛起。適用於需獨立提交/回滾的操作(如日誌記錄、審計)。
  • PROPAGATION_SUPPORTS:若當前存在事務則加入,否則以非事務方式執行。適合只讀查詢等無需事務保護的場景。
  • PROPAGATION_NOT_SUPPORTED:以非事務方式執行,若當前存在事務則掛起。用於明確不需要事務的外部服務調用。
  • PROPAGATION_NEVER:以非事務方式執行,若當前存在事務則拋出異常。強制要求非事務環境。
  • PROPAGATION_MANDATORY:若當前存在事務則加入,否則拋出異常。強制要求必須在事務中執行。
  • PROPAGATION_NESTED(Spring 專有):若當前存在事務則創建嵌套事務(基於 JDBC Savepoint),否則等同 REQUIRED。嵌套事務依賴外部事務提交,外部回滾會導致內部回滾,但內部回滾不影響外部。

實戰場景:第三方調用含事務 Service 拋異常分析

假設調用鏈:Consumer → methodA() → methodB(),雙方傳播屬性均為 REQUIRED。

public void methodA() {
    try {
        methodB();
    } catch (Exception e) {
        process(); // 處理異常但未重新拋出
    }
    otherOperation();
}

現象:UnexpectedRollbackException

當 methodB 拋出異常時,共享事務被標記為 rollback-only。雖然 methodA 捕獲了異常並正常執行完畢,但 Spring 在提交事務時發現事務已被標記回滾,因而拋出 UnexpectedRollbackException: "Transaction rolled back because it has been marked as rollback-only"。

根本原因

REQUIRED 傳播下,methodA 與 methodB 共用同一個物理事務。methodB 異常導致事務標記為僅回滾,而 methodA 未感知並嘗試正常提交,引發衝突。

解決方案與驗證

方案一:methodA 移除事務(SUPPORTS / NOT_SUPPORTED)

讓 methodA 不參與事務管理,避免提交衝突。

方案二:methodB 獨立事務(REQUIRES_NEW)

methodB 開啟新事務並掛起外部事務,內部異常回滾不影響外部事務狀態。

進階探討:已回滾事務能否重複回滾?

通過多次調用 methodB 並捕獲異常測試發現:事務被標記回滾後,後續操作仍可正常執行(如打印語句),推測 Spring 內部對已回滾事務的再次回滾操作採用「跳過」策略,不會重複執行回滾邏輯。

最佳實踐建議

  1. 明確業務邊界,合理選擇傳播行為,避免不必要的事務嵌套。
  2. 捕獲異常後若不重新拋出,需確認事務狀態或手動標記回滾(TransactionAspectSupport.currentTransactionStatus().setRollbackOnly())。
  3. 對於需獨立提交的操作(日誌、通知),優先使用 REQUIRES_NEW。
  4. 嵌套事務(NESTED)僅適用於 JDBC 數據源,且依賴數據庫對 Savepoint 的支援。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved