在系列第一部分,我們定義了事務與 ACID 特性。本文將揭開 J2EE 容器如何讓事務服務(劃分、資源徵用、事務傳播)對組件程式設計師幾乎隱形的「魔法」面紗。只要遵循幾條簡單規則,J2EE 應用就能自動獲得事務語義,幾乎無需額外程式碼。
JTS 是組件事務監視器(Component Transaction Monitor,CTM)。傳統事務處理監視器(TPM)管理程序化定義的事務;隨著 CORBA、RMI 等分散式物件協議出現,人們需要面向物件的事務模型。JTS 實現了 CORBA OTS 規範,充當 Java Transaction API (JTA) 與 OTS 之間的橋樑,實現 J2EE 與 CORBA 的互操作。
當 EJB 需要存取資料庫、JMS 隊列或 JCA 資源時,只需透過 JNDI 取得 DataSource 或 ConnectionFactory。容器提供的連線池會回傳包裝過的連線物件,在建立連線或執行 JDBC 操作時,包裝器會自動詢問事務管理器目前執行緒是否在事務上下文中,若是則自動將連線徵用進該事務。同樣機制適用於 JMS 與 JCA 資源。
// Bean 管理事務範例:無顯式徵用程式碼
UserTransaction ut = ejbContext.getUserTransaction();
ut.begin();
DataSource ds1 = (DataSource) ic.lookup("java:comp/env/OrdersDB");
DataSource ds2 = (DataSource) ic.lookup("java:comp/env/InventoryDB");
Connection con1 = ds1.getConnection(); // 自動徵用
Connection con2 = ds2.getConnection(); // 自動徵用
// ... 業務邏輯
ut.commit();
UserTransaction 顯式開始/結束。assembly-descriptor/container-transaction 中以 trans-attribute 宣告每個方法的事務語義,容器自動處理邊界。CMT 最大優勢在於事務語義與業務程式碼分離,組裝階段即可調整事務行為,無需修改原始碼。但這也要求組件開發者提供充分文檔,應用組裝者理解組件交互,才能在一致性與效能間取得平衡。
容器將事務上下文綁定於執行緒。本地呼叫自然共享同一執行緒;遠端 EJB 呼叫時,Stub 將事務識別符 (Xid) 作為 IIOP 呼叫的一部分傳播至遠端,Skeleton 在遠端執行緒重建事務上下文,使遠端方法同樣在該事務中執行。這讓 Servlet → Session Bean → Entity Bean 的完整呼叫鏈路能參與同一事務。

當容器偵測到事務中僅徵用單一資源管理器(如多個 Bean 存取同一資料庫),會自動跳過昂貴的兩階段提交 (2PC),改用單階段提交,顯著提升效能。
這套「魔法」非 JTS 獨有,而是 J2EE 容器整合 JTA/JTS、EJB Stub/Skeleton、JDBC 包裝器、JMS/JCA 提供者共同協作的結果。下一部分將討論事務劃分與隔離的實戰取捨。