在分佈式系統中,全局事務 (Global Transaction) 通常綁定在發起線程的 ThreadLocal 中。若主線程啟動事務後嘗試將事務上下文傳遞給子線程並發執行數據庫操作,標準 JTA 規範並不支持,WebLogic 也不例外。本文記錄一次利用 WebLogic 內部 API 打破此限制的嘗試,並深入分析其中的協調者選擇、XA 狀態衝突等隱患。
WebLogic 的 TransactionManagerImpl 通過 internalResume(Transaction) 將事務綁定到當前線程的 ThreadLocal,internalSuspend() 解除綁定。要在子線程中參與事務,子線程必須是 WebLogic 管理的 ExecuteThread 類型 (或繼承 AuditableThread),並調用此內部 API。
weblogic.kernel.AuditableThread。TransactionManagerImpl tm = (TransactionManagerImpl) TransactionManagerImpl.getTransactionManager();
tm.internalResume((TransactionImpl) tx); // 綁定事務
// 執行 JDBC/XA 操作
tm.internalSuspend(); // 解除綁定
commit() 或 rollback()。package weblogic.transaction.internal; // 必須放在此包以訪問 package-private API
public class DriverTest {
// ... 初始化 UserTransaction, 獲取 Transaction tx
// 關鍵:主線程先獲取一個連接指定協調者
Connection conn = getConnection("t3://localhost:8011", "TestXADS");
SQLThread t1 = new SQLThread(tx, result, "TestXADS", "t3://localhost:8011", SQL_INSERT);
SQLThread t2 = new SQLThread(tx, result, "TestXADS_1", "t3://localhost:8021", ANO_SQL_INSERT);
t1.start(); t2.start();
// 等待結果並提交/回滾
}
class SQLThread extends AuditableThread {
public void run() {
TransactionManagerImpl tm = ...getTransactionManager();
tm.internalResume((TransactionImpl)tx);
// 業務邏輯
tm.internalSuspend();
}
}
全局事務的第一個 XAResource 參與者所在的 Server 實例將成為協調者。測試代碼第 66 行主動獲取連接,強制指定 8011 為協調者。若省略,子線程並發啟動時各自嘗試成為協調者,導致 TransactionRolledbackException: Current server is the coordinator and transaction is not found。
若 Thread1 和 Thread2 同時操作同一 DataSource (XAResource),會並發調用 xaStart/xaEnd 並傳遞相同 Flag (如 TMSUSPEND),導致 XA 錯誤:XAER_RMERR: A resource manager error has occurred。結論:各線程必須操作互不相交的 DataSource 集合。
weblogic.transaction.internal.*),升級即失效。本文旨在深入理解 WebLogic 事務內部機制,**強烈不建議**在生產環境採用此方案。