1. 基本概念
事務(Transaction)是一組不可分割的操作單元,這些操作要么全部成功執行,要么全部失敗回滾,不存在部分成功的情況。
事務具有ACID特性:
- 原子性(Atomicity):事務是不可分割的最小單元。
- 一致性(Consistency):事務執行前后,數據狀態保持合法(如轉賬后總金額不變)。
- 隔離性(Isolation):多個事務并發執行時,彼此互不干擾。
- 持久性(Durability):事務提交后,數據變更永久保存。
2.核心接口
Spring通過抽象層封裝了不同的事務管理方式(如JDBC、Hibernate、MyBatis等),核心接口包括:
接口 | 作用 |
---|---|
PlatformTransactionManager | 事務管理器接口,定義了事務的提交、回滾等操作。 |
TransactionDefinition | 定義事務屬性(隔離級別、傳播行為、超時時間等)。 |
TransactionStatus | 表示事務的當前狀態(是否活躍、是否已提交等)。 |
常見實現類:
DataSourceTransactionManager
:用于JDBC或MyBatis的事務管理。HibernateTransactionManager
:用于Hibernate的事務管理。
3. 方式
聲明式事務管理
通過注解或XML配置聲明事務規則,無需手動編寫事務控制代碼,侵入性低,是實際開發的首選。
核心注解:@Transactional
可標注在類或方法上,用于聲明該類/方法需要事務管理。
示例:
@Service
public class UserService {// 聲明式事務:方法執行時自動開啟事務@Transactionalpublic void transferMoney() {// 業務邏輯:扣減A的余額,增加B的余額updateUserA();updateUserB();// 若方法正常結束,自動提交事務;若拋出異常,自動回滾}
}
4. @Transactional
注解的核心屬性
@Transactional
提供了豐富的屬性來配置事務行為:
屬性 | 作用 | 可選值示例 |
---|---|---|
propagation | 事務傳播行為(解決嵌套事務問題) | REQUIRED (默認)、REQUIRES_NEW 等 |
isolation | 事務隔離級別(解決并發問題) | READ_COMMITTED (默認)、SERIALIZABLE 等 |
readOnly | 是否為只讀事務(查詢操作可優化性能) | true /false (默認false) |
timeout | 事務超時時間(秒),超時自動回滾 | 如30 (30秒) |
rollbackFor | 指定觸發回滾的異常類型 | 如Exception.class |
noRollbackFor | 指定不觸發回滾的異常類型 | 如BusinessException.class |
關鍵屬性詳解
-
事務傳播行為(
propagation
)
定義了多個事務方法嵌套調用時,事務如何傳播。常見場景:REQUIRED
(默認):如果當前有事務,則加入;否則新建事務。REQUIRES_NEW
:無論當前是否有事務,都新建一個事務(原事務暫停)。SUPPORTS
:如果當前有事務,則加入;否則以非事務方式執行。
示例:
@Transactional(propagation = Propagation.REQUIRES_NEW) public void logOperation() {// 日志記錄,獨立事務,即使主事務回滾也會提交 }
-
事務隔離級別(
isolation
)
解決并發事務引發的問題(臟讀、不可重復讀、幻讀):READ_UNCOMMITTED
:最低級別,允許讀取未提交的數據(可能臟讀)。READ_COMMITTED
(默認):只能讀取已提交的數據(避免臟讀)。REPEATABLE_READ
:保證多次讀取同一數據結果一致(避免不可重復讀)。SERIALIZABLE
:最高級別,完全串行化執行(避免所有并發問題,但性能低)。
5. 事務回滾規則
- 默認情況下,
@Transactional
僅對未檢查異常(RuntimeException
及其子類) 觸發回滾,對已檢查異常(如IOException
) 不回滾。 - 可通過
rollbackFor = Exception.class
指定對所有異常回滾:@Transactional(rollbackFor = Exception.class) public void transferMoney() throws Exception {// 任何異常都會觸發回滾 }
6.實現原理
Spring聲明式事務基于AOP(面向切面編程) 實現:
- 當方法標注
@Transactional
時,Spring通過AOP動態生成代理對象。 - 代理對象在方法執行前開啟事務,執行后根據是否異常決定提交或回滾。
- 事務管理邏輯與業務邏輯解耦,通過"環繞通知"織入。
7. 常見問題與注意事項
-
@Transactional
失效場景:- 方法被
private
、final
修飾(AOP無法生成代理)。 - 同類中非事務方法調用事務方法(未經過代理對象)。
- 異常被
try-catch
捕獲但未重新拋出(Spring無法感知異常)。 - 數據庫引擎不支持事務(如MySQL的MyISAM,需改用InnoDB)。
- 方法被
-
自調用問題:
同類中方法A調用方法B(標注@Transactional
),事務會失效,因為未通過代理對象調用。
解決:注入自身Bean或使用AopContext.currentProxy()
獲取代理對象。 -
性能優化:
- 查詢操作設置
readOnly = true
(數據庫可優化)。 - 避免事務范圍過大(如將非數據庫操作移出事務)。
- 查詢操作設置
總結
Spring事務管理簡化了傳統JDBC事務的復雜性,聲明式事務(@Transactional
)因其低侵入性成為主流選擇。實際開發中需注意事務的傳播行為、隔離級別及失效場景,確保數據一致性的同時兼顧性能。