Spring 默認事務隔離級別為 ISOLATION_READ_COMMITTED,傳播行為為 PROPAGATION_REQUIRED (有事務則加入,無則新建)。本文通過一個巢狀調用案例,揭示默認配置下外層事務回滾導致內層已提交數據丟失的隱性風險。
class Sample { private int id; private String name; /* getter/setter */ }
class A {
@Transactional // 默認 REQUIRED
public void functionA(Sample sample) {
// 更新 sample
sampleDao.update(sample);
}
}
class B {
@Transactional // 默認 REQUIRED
public void functionB(List<Sample> samples) {
for (Sample s : samples) {
a.functionA(s); // 內層調用
}
// 業務邏輯可能拋出異常導致外層回滾
if (someCondition) throw new RuntimeException("Business error");
}
}
B.functionB() → 開啟事務 T_outer。A.functionA() → 偵測到現有事務 T_outer,**加入同一事務** (不開啟新事務)。functionA 執行 update,SQL 發送數據庫,但**未提交** (受 T_outer 控制)。functionB 拋出異常 → T_outer 標記回滾。T_outer,**所有 update 操作全部撤銷**。functionA 內部捕獲異常不拋出,外層不知情繼續提交,導致數據不一致。| 需求 | 傳播行為 | 適用場景 |
|---|---|---|
| 內層獨立提交,外層失敗不影響 | PROPAGATION_REQUIRES_NEW | 日誌記錄、審計、補償操作 |
| 內層必須在事務中,但不開啟新事務 | PROPAGATION_MANDATORY | 核心業務方法,強制調用方開啟事務 |
| 內層不需要事務 (如只讀查詢) | PROPAGATION_SUPPORTS 或 NOT_SUPPORTED | 查詢、報表生成 |
| 內層嵌套事務 (Savepoint),外層回滾可選擇回滾到嵌套點 | PROPAGATION_NESTED (僅 DataSourceTransactionManager 支援) | 複雜業務分步驟提交 |
propagation。REQUIRED 或 REQUIRES_NEW。rollbackFor = Exception.class 確保受檢異常也觸發回滾。readOnly = true,提示數據庫優化鎖策略。事務邊界設計是分層架構中最易被忽視卻影響最大的決策之一。理解
PROPAGATION_REQUIRED的「加入語義」而非「獨立語義」,是避免數據不一致、部分提交失敗的前提。