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

Spring + Hibernate 事務管理深度解析:聲明式事務配置、傳播行為與最佳實踐

     編輯:Java 綜合教學

從手動事務到聲明式事務的演進

純 Hibernate 時代,每次操作需手動開啟/提交/回滾事務,代碼分散、易漏提交、異常處理繁瑣。Spring 提供聲明式事務管理,通過 AOP 切面攔截 Service 方法,自動處理事務邊界,實現業務邏輯與事務邏輯解耦。

核心配置三步走

1. 配置事務管理器 (綁定 SessionFactory)

<bean id="transactionManager" 
      class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

Hibernate 5 使用 HibernateTransactionManager,Hibernate 4 同包路徑。事務管理器負責從 SessionFactory 獲取/綁定 Session 到線程局部變量,實現「一請求一 Session」。

2. 定義事務屬性 (傳播行為、隔離級別、只讀、超時)

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 增刪改方法:必須在事務中運行 -->
        <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="insert*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception"/>
        <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception"/>
        
        <!-- 查詢方法:只讀事務,優化資料庫鎖 -->
        <tx:method name="get*" propagation="NOT_SUPPORTED" read-only="true"/>
        <tx:method name="find*" propagation="NOT_SUPPORTED" read-only="true"/>
        <tx:method name="query*" propagation="NOT_SUPPORTED" read-only="true"/>
        <tx:method name="list*" propagation="NOT_SUPPORTED" read-only="true"/>
        <tx:method name="count*" propagation="NOT_SUPPORTED" read-only="true"/>
        
        <!-- 其他方法默認只讀 -->
        <tx:method name="*" read-only="true"/>
    </tx:attributes>
</tx:advice>

3. AOP 切點綁定 (Service 層織入)

<aop:config>
    <aop:pointcut id="serviceMethods" 
        expression="execution(* com.example.service..*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/>
</aop:config>

關鍵原則:事務邊界劃在 Service 層,而非 DAO 層。DAO 粒度太細,無法保證跨多個 DAO 操作的原子性;Service 組合業務邏輯,天然符合事務邊界。

七大傳播行為詳細對照表

常量 行為描述 典型場景
REQUIRED (默認) 有事務則加入,無則新建。最常用,保證同一邏輯事務。 增刪改業務方法
SUPPORTS 有事務則加入,無則以非事務運行。 查詢方法,允許在事務外獨立調用
MANDATORY 必須在現有事務中運行,否則拋異常。 強制要求事務上下文的核心操作
REQUIRES_NEW 總是新建事務,掛起現有事務。獨立提交/回滾。 日誌記錄、審計、獨立計費扣款
NOT_SUPPORTED 以非事務方式運行,掛起現有事務。 大批量只讀查詢、長時間報表導出
NEVER 非事務運行,若存在事務則拋異常。 嚴格禁止事務的外部接口調用
NESTED 嵌套事務 (Savepoint),外層回滾內層必回滾,內層回滾外層可選擇提交。 JDBC 支持 Savepoint 的數據庫,細粒度回滾

回滾規則:默認只回滾 RuntimeException

<tx:method name="transfer" propagation="REQUIRED" 
    rollback-for="java.lang.Exception" 
    no-rollback-for="com.example.BusinessWarningException"/>
  • rollback-for:指定需觸發回滾的異常 (含子類),建議設為 Exception 覆蓋所有受檢異常。
  • no-rollback-for:業務預期異常 (如庫存不足) 不回滾,交由上層處理。

註解驅動配置 (現代項目推薦)

<tx:annotation-driven transaction-manager="transactionManager" />
@Service
@Transactional(readOnly = true) // 類級別默認只讀
public class AccountServiceImpl implements AccountService {

    @Override
    @Transactional(readOnly = false, rollbackFor = Exception.class)
    public void transfer(Long from, Long to, BigDecimal amount) {
        // 業務邏輯...
    }

    @Override
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public AccountDTO getAccount(Long id) { ... }
}

事務與二級緩存的協同

事務配置在 Service 層對二級緩存 (Ehcache/Redis) 有益:

  1. 事務提交前,Hibernate 將實體保持在一級緩存 (Session) 中,不刷新二級緩存。
  2. 事務提交時,afterCompletion 觸發二級緩存更新,保證緩存與數據庫一致性。
  3. 若事務在 DAO 層,多次 DAO 調用中間可能出現緩存不一致窗口。

常見坑與避坑指南

  1. @Transactional 失效:內部方法調用 (this.xxx()) 繞過代理;私有/非 public 方法;異常被 catch 未拋出;數據源未配置事務管理器。修正: 注入自身 Bean 或調整方法訪問級別。
  2. 事務嵌套誤用 REQUIRES_NEW:外層回滾不影響內層已提交數據,導致不一致。修正: 僅在真正獨立業務 (日誌、審計) 使用。
  3. 只讀事務未生效:MySQL 需設置 readOnly=true 且連接池支持 (HikariCP 自動優化)。
  4. 跨數據源事務:單一 HibernateTransactionManager 不支持,需引入 JtaTransactionManager (Atomikos/Bitronix) 實現 XA 事務。

總結

Spring 聲明式事務通過 TransactionManager + tx:advice + AOP 或 @Transactional 實現業務與事務分離。核心決策:Service 層開啟事務、增刷改用 REQUIRED+rollbackFor=Exception、查詢用 NOT_SUPPORTED+readOnly、特殊獨立業務用 REQUIRES_NEW。配合合理的異常體系設計,構建健壯的數據一致性保障體系。

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