前言
Spring 事務管理是企業級應用數據一致性的基石。`@Transactional` 雖簡單,但參數組合極其豐富。本文系統梳理 **傳播行為、隔離級別、只讀、超時、回滾規則** 五大核心維度,並給出生產環境配置建議與避坑指南。
一、傳播行為:7 種模式對比
| 常量 | 行為描述 | 典型場景 | 注意點 |
| REQUIRED (默認) | 有事務則加入,無則新建 | 90% 業務方法 | 同一事務上下文,回滾波及所有 |
| SUPPORTS | 有事務則加入,無則以非事務運行 | 只讀查詢、報表導出 | 非事務模式下無回滾能力 |
| MANDATORY | 必須在現有事務中運行,否則拋異常 | 強制要求事務的核心業務 | 防止被誤調用於非事務環境 |
| REQUIRES_NEW | **掛起當前事務,新建獨立事務** | 日誌記錄、審計、獨立提交 | 外層回滾不影響內層,內層提交後外層回滾不撤銷內層 |
| NOT_SUPPORTED | 掛起當前事務,以非事務運行 | 長耗時非關鍵操作(如發郵件) | 避免長事務持有鎖 |
| NEVER | 不能在事務中運行,否則拋異常 | 嚴禁事務的工具方法 | 罕用 |
| NESTED | **基於 Savepoint 的嵌套事務** | 批量導入中單條失敗回滾 | 僅 JDBC/MyBatis 支援,Hibernate/JPA 不支援 |
二、隔離級別:平衡一致性與併發
| 級別 | 髒讀 | 不可重複讀 | 幻讀 | Spring 默認 |
| READ_UNCOMMITTED | ✅ | ✅ | ✅ | |
| READ_COMMITTED | ❌ | ✅ | ✅ | ✅ (大多數 DB 默認) |
| REPEATABLE_READ | ❌ | ❌ | ✅ | |
| SERIALIZABLE | ❌ | ❌ | ❌ | |
建議:默認 `READ_COMMITTED`(Oracle/PostgreSQL/SQL Server 默認),MySQL 默認 `REPEATABLE_READ` 亦可。**不要輕易升級至 SERIALIZABLE**,鎖競爭劇增。
三、只讀優化:readOnly = true
- **適用場景**:純查詢方法(Service 查詢、Controller 獲取詳情)。
- **效果**:
- Hibernate:Session 設置 `FlushMode.MANUAL`,跳過髒檢查、不產生 UPDATE SQL。
- JDBC:提示數據庫「只讀」,部分驅動/數據庫可優化執行計劃、避免鎖。
- 事務管理器:跳過事務同步註冊,減輕開銷。
- 前提:必須在**事務生效**的方法上標註,否則被忽略。
四、回滾規則:精準控制
@Transactional(
rollbackFor = {BizException.class, SQLException.class}, // 這些 checked exception 也回滾
noRollbackFor = {ValidationException.class} // 這些 runtime exception 不回滾
)
- 默認:**僅回滾 `RuntimeException` 及 `Error`**。
- Checked Exception 需顯式聲明 `rollbackFor`。
- 業務異常建議繼承 `RuntimeException`,天然觸發回滾,減少配置。
五、超時控制:timeout
@Transactional(timeout = 30) // 秒,超過拋 TransactionTimedOutException
- 底層靠數據庫鎖超時或事務管理器計時器實現,**不精確**,僅作保護網。
- 長事務建議拆分、異步化,而非依賴超時。
六、生產環境最佳實踐清單
- Service 層粒度開啟事務:Controller 不加 `@Transactional`,Service 方法根據業務邊界加。
- 查詢方法加 `readOnly = true`:如 `getUserById`、`listOrders`。
- 異步/定時任務用 `REQUIRES_NEW`** 避免污染主事務。
- 批量處理考慮 `NESTED` 或手動 Savepoint** 實現單條失敗不影響整體。
- 異常分層:業務異常 `extends RuntimeException`,系統異常走全局處理器,回滾語義清晰。
- 避免大事務:事務中不要做 RPC 調用、發送 MQ、大量計算,只做 DB 操作。
七、常見誤區
| 誤區 | 後果 | 正確做法 |
| Controller 加 @Transactional | 事務過大、視圖渲染在事務中、連接釋放延遲 | 只在 Service 加 |
| private 方法加 @Transactional | 代理不攔截,失效 | 只能用於 public 方法 |
| 同類內部調用事務方法 | 繞過代理,事務失效 | 注入自身 AopContext.currentProxy() 或拆分類 |
| catch 異常後不重拋 | 事務不回滾 | catch 後 throw new BizException(e) 或 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly() |
總結
Spring 事務管理核心在於**「傳播定義邊界、隔離定義一致性、只讀優化查詢、回滾規則精準化、超時兜底保護」**。掌握五大維度參數組合與七大避坑指南,即能在微服務、單體架構下構建健壯的數據一致性保障體系。
- 上一篇文章: 排序算法精讲:冒泡排序原理、代码实现与优化分析
- 下一篇文章: Servlet 基础回顾:接口五大方法、生命周期与手写 HelloWorld 实战
Copyright ©
程式碼之家 All Rights Reserved