隨著互聯網架構從單體邁向微服務,跨數據庫、跨服務的數據一致性成為核心挑戰。本文基於 IBM developerWorks 經典文檔與實戰經驗,系統闡述 JTA (Java Transaction API) 核心原理、XA 兩階段提交協議、事務管理器與資源管理器交互機制,並提供代碼級實現邏輯,幫助你透徹理解分布式事務「黑盒」內部運作。
事務四大特性 (ACID):
轉賬場景:A 賬戶 -500,B 賬戶 +500。無事務保護時,任一步失敗導致資金「憑空消失」或「憑空產生」,嚴重違反一致性。
Connection conn = dataSource.getConnection();
conn.setAutoCommit(false); // 關鍵:關閉自動提交
try {
stmt.execute("update account set amount=amount-500 where id='A'");
stmt.execute("update account set amount=amount+500 where id='B'");
conn.commit(); // 統一提交
} catch (Exception e) {
conn.rollback(); // 異常回滾
} finally {
close(conn, stmt);
}
Connection,無法跨多個數據庫。UserTransaction utx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
Connection connA = dsA.getConnection(); // XADataSource 獲取的 XAConnection
Connection connB = dsB.getConnection();
utx.begin();
try {
connA.createStatement().execute("update A set amount=amount-500");
connB.createStatement().execute("update B set amount=amount+500");
utx.commit(); // 統一提交兩個數據庫
} catch (Exception e) {
utx.rollback(); // 統一回滾
}

| 角色 | 接口/組件 | 職責 | 面向對象 |
|---|---|---|---|
| 應用開發者 | UserTransaction |
begin/commit/rollback/getStatus/setRollbackOnly | 開發接口 |
| 事務管理器 | TransactionManager、Transaction |
創建事務、關聯線程、協調資源、驅動 2PC | 橋梁接口 |
| 資源管理器 | XADataSource、XAConnection、XAResource |
實現 XA 協議,提供 prepare/commit/rollback | 提供商接口 (廠商實現) |
begin():TM 創建 Transaction 對象,綁定當前線程 (ThreadLocal)。commit():檢查 rollbackOnly 標記,委托 TM.commit()。rollback():委托 TM.rollback()。setRollbackOnly():標記當前事務只能回滾。begin():生成全局唯一 Xid,實例化 TransactionImpl,綁定線程。commit/rollback:從線程取 Transaction,調用其同名方法。getTransaction():獲取當前線程綁定事務。suspend/resume:掛起/恢復事務上下文(跨事務調用非事務操作)。enlistResource(XAResource, flag):將資源(如 XAConnection)登記到當前事務。delistResource:移除資源登記。registerSynchronization:註冊回調(如 Hibernate 緩存清理)。commit():驅動 2PC 核心邏輯(見下文)。為何代碼無顯式登記,資源却自動加入事務?關鍵在 XAConnection 創建的 Statement 被增強:
// XAStatement.execute() 內部邏輯
public void execute(String sql) {
associateWithTransactionIfNecessary(); // 關鍵攔截點
// 執行 SQL...
}
void associateWithTransactionIfNecessary() {
TransactionManager tm = getTransactionManager(); // 獲取 TM
Transaction tx = tm.getTransaction(); // 取當前線程事務
if (tx != null) { // 在事務中
Connection conn = this.getConnection();
if (!tx.hasCurrentResource(conn)) { // 未登記
XAConnection xaConn = (XAConnection) conn;
XADataSource xaSource = xaConn.getDataSource();
tx.enlistResource(xaSource.getXAResource(), 1); // 自動登記
}
}
}
結論:必須從實現 XADataSource 的數據源獲取連接,普通 DriverManager.getConnection() 無 XA 能力,操作不會被納入全局事務。

XAResource 發送 prepare()。redo/undo log,進入「萬事俱備,只欠東風」狀態(持有鎖,未提交)。XA_OK(準備就緒)或 XA_RB*(回滾)。XA_OK,TM 發送 commit(),RM 正式提交,釋放鎖。rollback(),所有 RM 回滾,釋放鎖。// TransactionImpl.commit()
public void commit() {
List resources = getAllEnlistedResources();
// 1. 準備階段
for (XAResource xa : resources) {
xa.prepare(); // 可能拋異常,生產級需異常處理
}
// 2. 提交階段
for (XAResource xa : resources) {
xa.commit(xid, false); // false=單階段提交標記,此處為二階段
}
}
formatID (int)、gtrid (byte[64]) 全局事務 ID、bqual (byte[64]) 分支修飾符。formatID=0 表示 OSI CCR 命名,>0 自定義格式,-1 無效。gtrid 標識全局事務,bqual 標識分支事務(如不同數據庫),全局唯一。| 類別 | 代表產品 | 適用場景 | 特點 |
|---|---|---|---|
| J2EE 容器內置 | JBoss/WildFly, WebLogic, WebSphere | 全棧 Java EE 應用 | 功能全、監控強、重、綁定容器 |
| 獨立 JTA 實現 | Atomikos, Bitronix, Narayana, JOTM | Tomcat, Jetty, Spring Boot, 獨立 Java 應用 | 輕量、嵌入式、無容器依賴 |
| Spring 事務抽象 | PlatformTransactionManager + JtaTransactionManager | Spring 生態統一事務編程模型 | 聲明式 @Transactional、統一異常轉換 |
xa.commit(),減少串行延遲。setTransactionTimeout 避免長事務佔用鎖導致死鎖/積壓。原則:能用本地事務絕不用分布式事務。只有業務強一致性要求極高(如資金轉賬、庫存扣減)且確需跨庫/跨服務時,才引入 JTA/XA。
XADataSource,使用 @Transactional 聲明式管理。XADataSource 而非普通 DataSource。JTA 通過 統一接口屏蔽異構資源差異,利用 ThreadLocal 綁定事務上下文,配合 XA 兩階段提交協議 實現跨資源管理器的原子性提交。理解其三大角色、兩階段流程、自動登記機制、Xid 唯一標識,是排查分布式事務異常、設計高可用系統的核心內功。技術無銀彈,分布式事務更是雙刃劍——在享受強一致性的同時,必須承擔性能損耗、複雜度提升、運維難度加大的代價。架構師的智慧,在於在業務容許範圍內,用最簡單的方案解決問題。