事務管理是企業級應用核心。Spring 提供統一抽象層,屏蔽底層資源 (JDBC、Hibernate、JPA、JMS) 差異。本文系統剖析 Spring 事務屬性、核心 API、編程式與聲明式四種演進方式,並給出生產環境最佳實踐建議。
| 常量 | 語意 | 防止 | 建議 |
|---|---|---|---|
| ISOLATION_DEFAULT | 資料庫預設 | - | 多數情況足夠 (通常=READ_COMMITTED) |
| ISOLATION_READ_UNCOMMITTED | 可讀未提交 | 無 | 極少用,髒讀風險 |
| ISOLATION_READ_COMMITTED | 可讀已提交 | 髒讀 | 推薦預設 |
| ISOLATION_REPEATABLE_READ | 可重複讀 | 髒讀、不可重複讀 | MySQL InnoDB 預設 |
| ISOLATION_SERIALIZABLE | 序列化 | 髒讀、不可重複讀、幻讀 | 效能極差,極少用 |
| 常量 | 行為 | 適用場景 |
|---|---|---|
| PROPAGATION_REQUIRED | 有事務加入,無則新建 | 90% 業務方法預設 |
| PROPAGATION_REQUIRES_NEW | 強制新事務,掛起現有 | 獨立審計日誌、通知發送 |
| PROPAGATION_SUPPORTS | 有則加入,無則非事務 | 唯讀查詢 |
| PROPAGATION_NOT_SUPPORTED | 非事務執行,掛起現有 | 長時間非 DB 操作 |
| PROPAGATION_NEVER | 非事務,有則拋異常 | 強制禁止事務 |
| PROPAGATION_MANDATORY | 必須在事務中,無則拋異常 | 核心業務強制事務 |
| PROPAGATION_NESTED | 巢狀事務 (Savepoint) | 部分回滾需求 (JDBC 支援) |
+Exception (不回滾) / -Exception (回滾)isNewTransaction()、setRollbackOnly()、isRollbackOnly()public boolean transfer(Long from, Long to, double amt) {
TransactionStatus status = txManager.getTransaction(txDef);
try {
boolean ok = dao.transfer(from, to, amt);
txManager.commit(status);
return ok;
} catch (Exception e) {
txManager.rollback(status);
return false;
}
}
缺點:樣板代碼散落、業務邏輯混雜。
public boolean transfer(final Long from, final Long to, final double amt) {
return transactionTemplate.execute(status -> {
try {
return dao.transfer(from, to, amt);
} catch (Exception e) {
status.setRollbackOnly();
return false;
}
});
}
TransactionCallback<T> / TransactionCallbackWithoutResultstatus.setRollbackOnly()手工配置攔截器、目標、代理,XML 膨脹嚴重。
合併攔截器與代理配置,仍需每個目標 Bean 一個定義。
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="svcPointcut" expression="execution(* com.example.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="svcPointcut"/>
</aop:config>
優點:切點表達式批量匹配、XML 精簡、功能最強。
@Transactional(propagation = Propagation.REQUIRED)
public boolean transfer(Long from, Long to, double amt) { ... }
啟用:<tx:annotation-driven transaction-manager="transactionManager"/>
| 維度 | <tx> + AOP | @Transactional |
|---|---|---|
| 批量匹配 | 切點表達式天然支援 | 需逐個標註 |
| 可讀性 | 集中配置,業務代碼零污染 | 註解直觀,但分散 |
| 彈性 | 極高 (任意切點、多 Advice) | 中等 |
| 學習曲線 | 需懂 AOP 切點語法 | 極低 |
| 建議場景 | 大型專案、統一事務策略、複雜切點 | 中小專案、快速開發、團隊熟悉註解 |