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

Spring 聲明式事務管理源碼深度解析:從配置解析到事務提交回滾全流程

     編輯:Java 相關知識

概覽:聲明式事務的三大核心支柱

Spring 聲明式事務管理將事務邏輯作為橫切關注點通過 AOP 織入業務代碼,實現了業務邏輯與事務控制的完全解耦。其核心實現圍繞三大模塊展開:

  1. 屬性解析與切點匹配:TransactionAttributeSourceAdvisor + TransactionAttributeSource 負責讀取註解/XML 配置,決定哪些方法需要什麼事務屬性。
  2. 事務創建與狀態管理:委託具體 PlatformTransactionManager 創建事務,通過 TransactionStatus 傳遞上下文。
  3. 事務邊界控制:TransactionInterceptor 作為環繞通知,在方法進出時完成事務的提交、回滾、掛起/恢復等全生命周期操作。

入口配置:TransactionProxyFactoryBean 的裝配邏輯

雖然現代 Spring 推薦使用 @EnableTransactionManagement + @Transactional,但理解經典的 TransactionProxyFactoryBean 有助於把握底層原理:

public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
    private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
    
    public void setTransactionManager(PlatformTransactionManager tm) {
        transactionInterceptor.setTransactionManager(tm);
    }
    public void setTransactionAttributes(Properties attrs) {
        transactionInterceptor.setTransactionAttributes(attrs);
    }
    
    protected Object createMainInterceptor() {
        transactionInterceptor.afterPropertiesSet();
        return (pointcut != null) 
            ? new DefaultPointcutAdvisor(pointcut, transactionInterceptor)
            : new TransactionAttributeSourceAdvisor(transactionInterceptor);
    }
}

關鍵點:

  • 內部持有一個 TransactionInterceptor 實例,所有事務屬性、事務管理器均注入該攔截器。
  • afterPropertiesSet() 中構建 ProxyFactory,將 Advisor 加入攔截器鏈,最終由 ProxyFactory 生成代理對象。

切點與屬性解析:TransactionAttributeSourceAdvisor

該 Advisor 內部定義了靜態切點 TransactionAttributeSourcePointcut,其匹配邏輯極其簡潔:

public boolean matches(Method method, Class targetClass) {
    TransactionAttributeSource tas = getTransactionAttributeSource();
    return (tas != null && tas.getTransactionAttribute(method, targetClass) != null);
}

即:只要能解析出非空的 TransactionAttribute,該方法就納入事務管理範圍。

屬性解析與緩存:AbstractFallbackTransactionAttributeSource

採用 模板方法 + 裝飾器模式,核心流程:

  1. 構建緩存 Key(方法 + 目標類)。
  2. 緩存命中直接返回;未命中調用 computeTransactionAttribute() 計算。
  3. 計算結果存入緩存(無屬性存入 NULL_TRANSACTION_ATTRIBUTE 哨兵對象)。

computeTransactionAttribute() 採用多級回退策略:

  1. 目標類中的具體方法
  2. 目標類上的類級別屬性
  3. 接口/父類中的對應方法
  4. 接口/父類上的類級別屬性

這完美支援了「類級別 @Transactional + 方法級別覆蓋」的語義。

事務攔截器核心:TransactionInterceptor.invoke()

public Object invoke(final MethodInvocation invocation) throws Throwable {
    Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;
    final TransactionAttribute txAttr = getTransactionAttributeSource()
        .getTransactionAttribute(invocation.getMethod(), targetClass);
    final String joinpointId = methodIdentification(invocation.getMethod());
    
    if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
        // 標準模式:手動控制事務邊界
        TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointId);
        try {
            return invocation.proceed();
        } catch (Throwable ex) {
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        } finally {
            cleanupTransactionInfo(txInfo);
        }
    } else {
        // 回調模式:委託事務管理器執行模板回調
        return ((CallbackPreferringPlatformTransactionManager) getTransactionManager())
            .execute(txAttr, status -> {
                TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointId, status);
                try {
                    return invocation.proceed();
                } finally {
                    cleanupTransactionInfo(txInfo);
                }
            });
    }
}

兩種模式本質一致:獲取事務屬性 → 創建/加入事務 → 執行業務 → 根據結果提交或回滾 → 清理上下文。

事務創建模板:AbstractPlatformTransactionManager.getTransaction()

定義了事務創建的標準流程(模板方法模式):

  1. doGetTransaction():子類獲取底層事務對象(如 JDBC Connection、Hibernate Session)。
  2. 判斷是否存在現有事務(isExistingTransaction())。
  3. 存在事務 → handleExistingTransaction() 根據傳播行為處理(掛起、嵌套、拋異常等)。
  4. 無現有事務 → 根據傳播行為決定:
    • REQUIRED/REQUIRES_NEW/NESTED → doBegin() 創建新事務。
    • SUPPORTS/NOT_SUPPORTED/NEVER → 不創建事務,返回空狀態。
    • MANDATORY → 拋異常。
  5. 構建 TransactionStatus 封裝事務狀態(是否新事務、是否有保存點、同步標記等)。

具體事務管理器實現:DataSourceTransactionManager

事務啟動:doBegin()

  • 從 DataSource 獲取 Connection。
  • 關閉自動提交 con.setAutoCommit(false)。
  • 設置隔離級別、只讀標記。
  • 將 ConnectionHolder 綁定到 TransactionSynchronizationManager(ThreadLocal),實現同線程事務上下文共享。

提交與回滾

protected void doCommit(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    con.commit(); // 核心:JDBC 原生提交
}

protected void doRollback(DefaultTransactionStatus status) {
    Connection con = txObject.getConnectionHolder().getConnection();
    con.rollback(); // 核心:JDBC 原生回滾
}

最終都歸結為對 JDBC Connection 的原生操作,Spring 只是負責管理 Connection 的生命週期與線程綁定。

事務同步與資源管理:TransactionSynchronizationManager

這是 Spring 事務生態的「粘合劑」:

  • 基於 ThreadLocal> 存儲資源綁定(Key 為 DataSource/SessionFactory,Value 為 Holder)。
  • 支援事務同步註冊(registerSynchronization()),在事務提交/回滾前後觸發回調(如 Hibernate flush、延遲加載檢查)。
  • 提供 bindResource()/unbindResource() 供事務管理器綁定/解綁底層資源。

編程式 vs 聲明式:本質對比

編程式事務本質是手動調用模板:

TransactionStatus status = txManager.getTransaction(def);
try {
    // business logic
    txManager.commit(status);
} catch (Exception ex) {
    txManager.rollback(status);
    throw ex;
}

聲明式事務只是將這段樣板代碼封裝進 TransactionInterceptor,並通過 AOP 自動織入,**核心邏輯完全一致**。

總結與最佳實踐建議

  • 傳播行為選型:90% 場景用 REQUIRED;需獨立事務用 REQUIRES_NEW;嵌套保存點用 NESTED(需數據庫支援)。
  • 只讀優化:@Transactional(readOnly = true) 可提示數據庫/連接池優化,Hibernate 會將 FlushMode 設為 NEVER。
  • 異常回滾規則:默認只回滾 RuntimeException/Error;受檢異常需 rollbackFor 指定。
  • 避免自我調用失效:同類內部方法調用繞過代理,需注入自身代理或使用 AspectJ 編織。
  • 事務邊界不宜過大:長事務佔用連接資源,增加鎖競爭與死鎖風險。

Spring 聲明式事務的優雅在於:將複雜的事務協議標準化為統一的 SPI 接口,將業務無關的樣板代碼集中到攔截器,將配置元數據解耦為可插拔的屬性源解析器。這正是 Spring「在核心複雜度換取用戶簡單度」設計哲學的經典體現。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved