Spring Framework 作為輕量級 J2EE 應用框架,其核心優勢在於 IoC 容器與強大的事務管理能力。Spring 的聲明式事務可應用於任意 POJO,功能對標 EJB 容器管理事務 (CMT),並支援從簡單 JDBC 事務到完整 JTA 分散式事務的多種後端策略。本文詳細探討 Spring 事務管理機制,重點講解基於 JTA 的聲明式事務配置、事務傳播行為、與 J2EE 伺服器事務協調器的無縫整合,展示其作為傳統 EJB CMT 替代方案的可行性。
以 Spring 經典 PetClinic 應用的核心服務 Clinic 為例,展示標準 XML Bean 定義:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"><value>java:comp/env/jdbc/petclinic</value></property>
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
<bean id="clinicTarget" class="org.springframework.samples.petclinic.jdbc.JdbcClinic">
<property name="dataSource"><ref bean="dataSource"/></property>
</bean>
<bean id="clinic" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref bean="transactionManager"/></property>
<property name="target"><ref bean="clinicTarget"/></property>
<property name="transactionAttributes">
<props>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="store*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
JtaTransactionManager,委託 J2EE 伺服器事務協調器。JdbcClinic),封裝業務與資料存取邏輯,無需感知 Spring。TransactionProxyFactoryBean 為目標服務織入事務行為,根據方法名模式匹配事務屬性。補充: Spring 亦支援 Commons Attributes 或 JDK 5.0 Annotation 實現自動代理與原始碼級元資料配置,本文不贅述。
public interface Clinic {
Pet loadPet(int id);
void storePet(Pet pet);
// ...
}
public class JdbcClinic implements Clinic {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; }
public Pet loadPet(int id) {
try (Connection con = dataSource.getConnection()) { /* JDBC 操作 */ }
catch (SQLException ex) { /* 異常處理 */ }
}
public void storePet(Pet pet) {
try (Connection con = dataSource.getConnection()) { /* JDBC 操作 */ }
catch (SQLException ex) { /* 異常處理 */ }
}
}
代碼簡潔純粹,事務管理由代理層完全接管。實際專案中建議搭配 Spring JDBC 模板類 (JdbcTemplate) 簡化資源管理。
客戶端獲取 clinic Bean 實為事務代理,調用方法時隱式觸發「事務攔截器」:

圖 1:具備「Advisor 鏈」與目標對象的 AOP 代理結構
WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(servletContext);
Clinic clinic = (Clinic) ctx.getBean("clinic");
Pet pet = new Pet(); pet.setName("my new cat");
clinic.storePet(pet); // 隱式開啟事務,方法結束提交/回滾
事務屬性中最關鍵的是傳播行為,定義方法調用時事務邊界處理方式:
| 傳播常量 | 行為描述 | 對應 EJB CMT |
|---|---|---|
| PROPAGATION_REQUIRED | 支援當前事務,不存在則新建 (最常用) | Required |
| PROPAGATION_SUPPORTS | 支援當前事務,不存在則非事務執行 | Supports |
| PROPAGATION_MANDATORY | 必須在事務中執行,否則拋出異常 | Mandatory |
| PROPAGATION_REQUIRES_NEW | 新建事務,掛起當前事務 | RequiresNew |
| PROPAGATION_NOT_SUPPORTED | 非事務執行,掛起當前事務 | NotSupported |
| PROPAGATION_NEVER | 非事務執行,存在事務則拋出異常 | Never |
| PROPAGATION_NESTED | 巢狀事務 (需 JDBC 3.0 Savepoint 或 JTA 支援) | Spring 專屬擴展 |
前六種策略與 EJB CMT 常量名一致,EJB 開發者極易上手。PROPAGATION_NESTED 是 Spring 獨有擴展,需底層事務管理器支援保存點機制。
-PetClinicException 表示拋出該檢查型異常時回滾。<prop key="load*">PROPAGATION_REQUIRED,readOnly,-PetClinicException</prop>
Spring 事務抽象核心為 PlatformTransactionManager 介面,提供多種實現:
| 類別 | 實現類 | 適用場景 |
|---|---|---|
| 本地事務 | DataSourceTransactionManager | 單一資料庫 (JDBC) |
| 本地事務 | HibernateTransactionManager | 單一資料庫 (Hibernate) |
| 全域事務 | JtaTransactionManager | 跨多資源 (J2EE 伺服器 JTA) |
核心價值:應用代碼與聲明式事務解耦,僅需切換 TransactionManager 實現即可適應不同部署環境 (如 Tomcat + 單庫 → WebLogic + 多庫),無需修改業務代碼。
標準 JtaTransactionManager 預設從 java:comp/UserTransaction 獲取 UserTransaction,**不支援事務掛起** (即 PROPAGATION_REQUIRES_NEW、PROPAGATION_NOT_SUPPORTED 失效),因 UserTransaction 缺乏 suspend/resume 方法。
解決方案:注入 JTA TransactionManager 實例 (提供標準掛起/恢復 API)。但 J2EE 未規範其 JNDI 名稱,需廠商特定配置:
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName"><value>vendorSpecificJndiLocation</value></property>
</bean>
javax.transaction.TransactionManager。WebLogicJtaTransactionManager 適配器,額外支援:
forceResume())。
圖 2:WebLogic Server 事務監控主控台
Spring 提供了全方位、非侵入式的事務管理解決方案:
PlatformTransactionManager 抽象屏蔽底層差異,實現策略熱插拔。