事務管理是企業級應用的基石。Spring 提供了聲明式事務管理,將事務邏輯與業務代碼分離,實現「配置而非編碼」。本文不再給出 Hello World 示例,而是從原理、配置維度、優缺點對比、進階屬性、最佳實踐五個維度深度解析兩大主流方式:基於 AOP 的 XML 配置 與 基於 @Transactional 註解,幫助架構師做出選型決策。
核心思想:利用 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 |
openSession():每次創建新 Session,需手動 close(),不受 Spring 事務管理。getCurrentSession():返回當前事務綁定的 Session,由 Spring 自動開啟/關閉/刷新,**必須配置 hibernate.current_session_context_class=org.springframework.orm.hibernate5.SpringSessionContext**。<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
}
| 屬性 | 默認值 | 說明 |
|---|---|---|
| propagation | REQUIRED | 傳播行為:REQUIRED、REQUIRES_NEW、NESTED、SUPPORTS 等 7 種 |
| isolation | DEFAULT | 隔離級別:READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE |
| timeout | -1 | 超時秒數,-1 使用底層數據庫默認 |
| readOnly | false | 只讀優化提示,適用於查詢方法 |
| rollbackFor | RuntimeException/Error | 觸發回滾的異常類數組 |
| noRollbackFor | 無 | 不觸發回滾的異常類數組 |
| 維度 | AOP XML | @Transactional |
|---|---|---|
| 耦合度 | 低:業務代碼零註解,純 POJO | 高:業務類依賴 Spring 註解 |
| 可讀性 | 低:事務邏輯分散在 XML,需跳轉文件 | 高:註解在方法上,上下文即可見 |
| 維護性 | 高:統一修改 XML,批量調整策略 | 低:分散在各類中,批量修改需全局搜索 |
| 靈活性 | 高:支持複雜切點表達式、多 advice 組合 | 中:方法級精細控制,但跨切面組合受限 |
| 適用場景 | 大型團隊、嚴格分層架構、需要集中治理事務策略 | 中小項目、敏捷開發、微服務單模塊 |
| 測試友好度 | 高:單元測試可不加載事務配置 | 中:需啟用 @Transactional 或模擬事務管理器 |
| 遷移成本 | 低:移除 XML 即可 | 高:需清理所有註解 |
DAO 僅做單表操作,事務邊界應在 Service 方法上,保證業務原子性。
@Transactional(readOnly = true, propagation = Propagation.SUPPORTS)
public List<User> findAll() { ... }
默認只回滾 RuntimeException/Error,受檢異常不回滾。業務中常拋出自定義受檢異常,務必顯式聲明:
@Transactional(rollbackFor = {BizException.class, DataAccessException.class})
public void transfer(TransferDTO dto) throws BizException { ... }
同一類內部方法調用帶 @Transactional 的方法,**事務不生效**(繞過代理)。解決方案:
@Autowired SelfService self 並調用 self.method()@Async 方法在線程池執行,事務上下文不傳播。需在異步方法內部程序化控制或調用獨立的事務性 Service。
選 AOP XML,如果:
選 @Transactional,如果:
混合模式(推薦): 基礎設施層(如通用 Service 基類)用 XML 定義默認事務模板,業務具體實現類用 @Transactional 覆蓋/細化。兼得集中治理與靈活性。
聲明式事務是 Spring 最成功的抽象之一。理解 AOP XML 的集中治理優勢 與 @Transactional 的就近可讀性 的本質權衡,結合團隊規模、架構風格、演進階段做選擇,並遵循「Service 層開啟、顯式回滾、只讀優化、避免自我調用」等鐵律,才能構建健壯、可維護的事務邊界。