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

Spring 聲明式事務管理深度解析:AOP XML vs @Transactional 選型指南

     編輯:Java 相關知識

前言

事務管理是企業級應用的基石。Spring 提供了聲明式事務管理,將事務邏輯與業務代碼分離,實現「配置而非編碼」。本文不再給出 Hello World 示例,而是從原理、配置維度、優缺點對比、進階屬性、最佳實踐五個維度深度解析兩大主流方式:基於 AOP 的 XML 配置 與 基於 @Transactional 註解,幫助架構師做出選型決策。

聲明式事務本質

核心思想:利用 AOP 動態代理,在目標方法執行前開啟事務,執行後提交/回滾。業務代碼零感知,事務屬於「系統級關注點」,而非業務邏輯一部分。

優勢:

  • 非侵入式:業務類無事務 API 依賴
  • 集中管理:修改事務策略只改配置,無需重新編譯業務代碼
  • 靈活性:支持傳播行為、隔離級別、超時、只讀、回滾規則等細粒度控制

方式一:AOP XML 配置(基於 tx/aop 命名空間)

核心配置結構

<beans xmlns="https://www.springframework.org/schema/beans"
       xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="https://www.springframework.org/schema/aop"
       xmlns:tx="https://www.springframework.org/schema/tx"
       xsi:schemaLocation="...>

    <!-- 1. 數據源 & DataSource -->
    <bean id="dataSource" class="..."></bean>

    <!-- 2. 事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 3. 事務屬性定義(通用/方法級) -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="get*" read-only="true" propagation="SUPPORTS"/>
            <tx:method name="find*" read-only="true" propagation="SUPPORTS"/>
            <tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="*" propagation="REQUIRED"/> <!-- 兜底 -->
        </tx:attributes>
    </tx:advice>

    <!-- 4. AOP 切面:將事務通知織入目標 Bean -->
    <aop:config>
        <aop:pointcut id="servicePointcut" expression="execution(* com.example.service.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
    </aop:config>
</beans>

關鍵點解析

元素作用注意事項
tx:advice定義事務語義(傳播、隔離、超時、只讀、回滾異常)可定義多個 advice,針對不同服務層
tx:method方法名模式匹配(支持 * 通配符)匹配順序由上至下,首個匹配生效
aop:pointcut切點表達式,定義哪些類/方法被代理建議精確到 service 包,避免誤織入
aop:advisor將 advice 綁定到 pointcut一個 advisor 對應一個 advice + pointcut

Session 管理關鍵:getCurrentSession() vs openSession()

  • openSession():每次創建新 Session,需手動 close(),不受 Spring 事務管理。
  • getCurrentSession():返回當前事務綁定的 Session,由 Spring 自動開啟/關閉/刷新,**必須配置 hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext**。
  • 聲明式事務下**必須使用 getCurrentSession()**,否則事務不生效且易洩漏 Session。

方式二:@Transactional 註解驅動

啟用配置

<beans ... xmlns:tx="https://www.springframework.org/schema/tx">
    <tx:annotation-driven transaction-manager="transactionManager" />
    <!-- 或 Java Config: @EnableTransactionManagement -->
</beans>

使用方式

@Service
@Transactional(readOnly = true)  // 類級別:默認所有方法只讀
public class UserServiceImpl implements UserService {

    @Override
    @Transactional(readOnly = false, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void save(User user) { ... }

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW, timeout = 30)
    public void auditLog(Audit log) { ... }  // 獨立事務

    @Override
    public User findById(Long id) { ... }  // 繼承類級 readOnly=true
}

常用屬性速查表

屬性默認值說明
propagationREQUIRED傳播行為:REQUIRED、REQUIRES_NEW、NESTED、SUPPORTS 等 7 種
isolationDEFAULT隔離級別:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE
timeout-1超時秒數,-1 使用底層數據庫默認
readOnlyfalse只讀優化提示,適用於查詢方法
rollbackForRuntimeException/Error觸發回滾的異常類數組
noRollbackFor無不觸發回滾的異常類數組

兩種方式深度對比

維度AOP XML@Transactional
耦合度低:業務代碼零註解,純 POJO高:業務類依賴 Spring 註解
可讀性低:事務邏輯分散在 XML,需跳轉文件高:註解在方法上,上下文即可見
維護性高:統一修改 XML,批量調整策略低:分散在各類中,批量修改需全局搜索
靈活性高:支持複雜切點表達式、多 advice 組合中:方法級精細控制,但跨切面組合受限
適用場景大型團隊、嚴格分層架構、需要集中治理事務策略中小項目、敏捷開發、微服務單模塊
測試友好度高:單元測試可不加載事務配置中:需啟用 @Transactional 或模擬事務管理器
遷移成本低:移除 XML 即可高:需清理所有註解

進階最佳實踐

1. 分層事務策略:Service 層開啟,DAO 層不開啟

DAO 僅做單表操作,事務邊界應在 Service 方法上,保證業務原子性。

2. 只讀事務優化查詢性能

@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public List<User> findAll() { ... }
  • Hibernate:自動將 Session 設置為 FlushMode.MANUAL,跳過髒檢查。
  • MyBatis:提示數據庫優化執行計劃(如 Oracle SELECT ... FOR UPDATE 跳過)。

3. 異常回滾規則顯式化

默認只回滾 RuntimeException/Error,受檢異常不回滾。業務中常拋出自定義受檢異常,務必顯式聲明:

@Transactional(rollbackFor = {BizException.class, DataAccessException.class})
public void transfer(TransferDTO dto) throws BizException { ... }

4. 避免「自我調用」失效

同一類內部方法調用帶 @Transactional 的方法,**事務不生效**(繞過代理)。解決方案:

  • 拆分到不同 Bean
  • 注入自身 @Autowired SelfService self 並調用 self.method()
  • 使用 AspectJ 編織(LTW/CTW)替代表 JDK 動態代理

5. 異步方法不可直接使用 @Transactional

@Async 方法在線程池執行,事務上下文不傳播。需在異步方法內部程序化控制或調用獨立的事務性 Service。

總結與選型建議

選 AOP XML,如果:

  • 團隊規模大,架構師統一制定事務規範
  • 項目嚴格分層,Service/DAO 包結構固定
  • 需頻繁批量調整事務策略(如全局調整隔離級別)
  • 希望業務代碼完全不依賴 Spring

選 @Transactional,如果:

  • 中小團隊,追求開發效率與代碼可讀性
  • 微服務架構,單模塊代碼量可控
  • 方法級事務差異大,需要精細控制
  • 使用 Spring Boot,註解驅動為主流風格

混合模式(推薦): 基礎設施層(如通用 Service 基類)用 XML 定義默認事務模板,業務具體實現類用 @Transactional 覆蓋/細化。兼得集中治理與靈活性。

結語

聲明式事務是 Spring 最成功的抽象之一。理解 AOP XML 的集中治理優勢 與 @Transactional 的就近可讀性 的本質權衡,結合團隊規模、架構風格、演進階段做選擇,並遵循「Service 層開啟、顯式回滾、只讀優化、避免自我調用」等鐵律,才能構建健壯、可維護的事務邊界。

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