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

@Transactional 深度解析:傳播行為、多線程、繼承優先級、AOP 織入與可見度陷阱

     編輯:Java 綜合教學

Spring 聲明式事務管理核心註解全方位剖析

@Transactional 是 Spring 事務抽象的入口,底層基於 AOP 實現方法級攔截。本文從事務基礎、傳播行為、多線程隔離、繼承機制、AOP 配置替代、方法可見度限制六大維度深度解析,附日誌驗證實例。

事務基礎回顧:ACID 與管理模式

  • ACID:原子性、一致性、隔離性、持久性。
  • 編程式:手動 begin/commit/rollback,侵入業務代碼。
  • 聲明式 (AOP):配置切面,方法前開啟/加入事務,後根據異常提交/回滾,業務零侵入。

啟用聲明式事務

<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="emf"/>
</bean>
<tx:annotation-driven transaction-manager="txManager"/>

或 Java Config:@EnableTransactionManagement。

核心屬性速查

傳播行為實戰驗證


// 呼叫鏈: PayHisInfoService.update() → save() → PayInfoService.update()
@Service @Transactional(propagation=REQUIRED)
class PayHisInfoService {
    @Autowired PayInfoService payInfoService;
    public void update(PayHisInfo his, PayInfo info) {
        save(his);                    // 同類內部調用,無事務傳播
        payInfoService.update(info);  // 跨 Bean,發生傳播
    }
    public void save(PayHisInfo his) { ... }
}

@Service
class PayInfoService {
    @Transactional(propagation=SUPPORTS, readOnly=true)
    public List findAll() { ... }
    public void update(PayInfo info) { ... }  // 繼承類級 REQUIRED
}

日誌證據:Participating in existing transaction 表明 PayInfoService.update 加入了外層事務,而非新建。

多線程環境下的事務隔離

若 PayHisInfoService.update 啟動新執行緒呼叫 PayInfoService.update:

  • 主線程與子線程各自擁有獨立事務(ThreadLocal 綁定 Connection)。
  • 子線程異常不會 自動回滾主線程事務,需手動協調(如 CompletableFuture + 異常傳遞)。
  • 結論:Spring 事務管理是線程安全的,但事務上下文不跨線程傳播。

@Transactional 繼承與優先級規則

  1. 類級註解:父類標註 @Transactional,子類所有 public 方法 自動獲得事務增強(無需重複標註)。
  2. 方法級覆蓋:子類重寫父類方法並標註 @Transactional,子類屬性優先,父類配置被忽略。
  3. 測試基類實用模式:
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("/applicationContext.xml")
    @TransactionConfiguration(transactionManager="txManager", defaultRollback=true)
    @Transactional
    public class BaseTest extends AbstractTransactionalJUnit4SpringContextTests { ... }
    所有繼承 BaseTest 的測試類方法自動在事務中執行,測試完自動回滾,極適合整合測試。

純 AOP XML 配置替代註解

<aop:config proxy-target-class="true">
    <aop:pointcut id="svcPointcut" expression="execution(public * com.xxx.service..*(..))"/>
    <aop:advisor pointcut-ref="svcPointcut" advice-ref="txAdvice"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

優點:集中管理、無註解汙染、支援通配符批量匹配。缺點:重構時切點表達式易失效。

方法可見度陷阱(必讀)

❌ 以下情況 @Transactional 失效:
  • 方法非 public(protected/private/package-private)。
  • 類內部自調用(this.method()),繞過代理。
  • 介面方法標註但使用 CGLIB 代理 (proxy-target-class=true) 且未實現介面。
  • 註解在介面/介面方法上,但代理模式為 CGLIB(預設 Spring Boot 2.x+)。

最佳實踐:僅在具體類的 public 方法上標註,內部調用需注入自身 @Autowired SelfService self 或使用 AopContext.currentProxy()(需 exposeProxy=true)。

源碼級驗證:CglibAopProxy.intercept 流程

  1. 攔截器鏈構建:advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass)。
  2. 若鏈為空且方法 public → 直接反射調用目標(無事務)。
  3. 否則構建 CglibMethodInvocation,呼叫 proceed() 鏈式執行攔截器。
  4. TransactionInterceptor 執行事務邏輯:invokeWithinTransaction → PlatformTransactionManager.getTransaction → 目標方法 → commit/rollback。

總結速記卡

  • 聲明式 > 編程式;@EnableTransactionManagement 一鍵啟用。
  • 傳播行為決定事務邊界:REQUIRED 多數場景足夠,REQUIRES_NEW 獨立提交(如日誌寫入)。
  • 事務綁定線程,跨線程需自行協調。
  • 父類類級註解自動遞傳,子類方法級可覆蓋。
  • 只能用於 public 方法,內部調用失效。
  • XML AOP 適合統一規範,註解適合精細控制,二選一避免混用。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
屬性說明常用值
propagation傳播行為REQUIRED(預設)、SUPPORTS、REQUIRES_NEW、NESTED...
isolation隔離級別READ_COMMITTED(多數 DB 預設)、REPEATABLE_READ、SERIALIZABLE
readOnly只讀優化true/false(預設)
timeout超時秒數-1(預設無超時)
rollbackFor觸發回滾的異常Exception.class(預設僅 RuntimeException/Error)
noRollbackFor不回滾的異常特定業務異常