@Transactional(noRollbackFor = RuntimeException.class) // 遇到運行時異常也不回滾
@Transactional(rollbackFor = Exception.class) // 遇到任何檢查型異常也回滾
默認:僅回滾 RuntimeException / Error。
| 傳播類型 | 場景 | 外層有事務 | 外層無事務 | 關鍵現象 |
|---|---|---|---|---|
| REQUIRED | 最常用 | 加入外層事務 | 新建事務 | 內層拋 RuntimeException → 整體回滾 |
| SUPPORTS | 唯讀輔助 | 加入外層事務 | 無事務運行 | 外層無事務時內層自動提交 |
| MANDATORY | 強制事務 | 加入外層事務 | ❌ 拋異常 | 禁止無事務調用 |
| REQUIRES_NEW | 獨立事務 | 掛起外層,新建事務 | 新建事務 | 內層提交/回滾不影響外層 |
| NOT_SUPPORTED | 非事務操作 | 掛起外層,無事務運行 | 無事務運行 | 適合長耗時查詢、外部調用 |
| NEVER | 禁用事務 | ❌ 拋異常 | 無事務運行 | 嚴禁事務上下文 |
| NESTED | 嵌套事務 | 創建 Savepoint | 同 REQUIRED | 內層回滾到 Savepoint,外層可繼續 |
// 外層 REQUIRED
@Transactional(propagation = Propagation.REQUIRED)
public void outer(User u) {
dao.insert(u); // 1
try { inner(null); } // 2 內層拋 RuntimeException
catch (RuntimeException e) { dao.insert(new User(500,"fsd")); } // 3 補償
}
// 內層 NESTED
@Transactional(propagation = Propagation.NESTED)
public void inner(User u) {
dao.insert(u); throw new RuntimeException();
}
// 結果:outer 1 提交,2 回滾到 Savepoint,3 提交 → 庫中有 1 和 3
| 級別 | 髒讀 | 不可重複讀 | 幻讀 | 鎖粒度 | 驗證現象 |
|---|---|---|---|---|---|
| READ_COMMITTED | ✓ | ✗ | ✗ | 行鎖(讀) | 外層未提交 INSERT,內層查不到 |
| READ_UNCOMMITTED | ✗ | ✗ | ✗ | 無讀鎖 | 可讀到未提交數據(髒讀) |
| REPEATABLE_READ | ✓ | ✓ | ✗ | 範圍鎖 | 同一事務兩次查詢結果集一致 |
| SERIALIZABLE | ✓ | ✓ | ✓ | 表鎖 | 完全串行,併發極低 |
@Transactional(isolation = Isolation.READ_COMMITTED) // 默認 DEFAULT(用數據庫預設)
@Transactional(isolation = Isolation.REPEATABLE_READ)
@Transactional(isolation = Isolation.SERIALIZABLE)
實驗建議:用斷點凍結外層事務,觀察內層可見性,親身體會隔離級別差異。