在 WebLogic 環境下整合 JMS 與 JTA 時,若發現 UserTransaction 回滾無效、訊息仍被發送或消費,通常是因為連線工廠與連線類型選擇錯誤。本文針對常見程式碼錯誤進行分析並給出正確配置。
生產者與消費者均使用 weblogic.jms.ConnectionFactory 建立 Connection,並設定 createSession(false, Session.AUTO_ACKNOWLEDGE),同時透過 JNDI 取得 UserTransaction 管理全域事務:
UserTransaction tx = (UserTransaction) context.lookup("javax.transaction.UserTransaction");
tx.begin();
Connection conn = cf.createConnection(); // 普通 Connection
Session session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 發送/接收訊息
tx.commit(); // 或 tx.rollback()
現象:拋出例外呼叫 tx.rollback() 後,訊息仍進入隊列或被消費,全域事務未生效。
普通 ConnectionFactory 建立的 Connection 不支援 XA 事務,無法納入 JTA 全域事務管理。 JTA 需要資源管理器(如 JMS Provider)實作 XAResource 介面,WebLogic 中必須使用 XA 版本的連線工廠與連線:
weblogic.jms.XAConnectionFactoryjavax.jms.XAConnection / XASession// 1. 查找 XA 連線工廠
String XA_CF_JNDI = "weblogic.jms.XAConnectionFactory";
XAConnectionFactory xacf = (XAConnectionFactory) context.lookup(XA_CF_JNDI);
// 2. 取得 XAConnection
XAConnection xaConn = xacf.createXAConnection();
// 3. 取得 XASession(事務由 JTA 控制,此處 transacted=false)
XASession xaSession = xaConn.createXASession();
// 4. 訊息發送/接收邏輯保持不變
// ...
// 5. 由 UserTransaction 統一提交/回滾
UserTransaction tx = (UserTransaction) context.lookup("javax.transaction.UserTransaction");
tx.begin();
// 業務操作
tx.commit(); // 或 tx.rollback()
| 項目 | 錯誤用法(本地事務) | 正確用法(JTA 全域事務) |
|---|---|---|
| ConnectionFactory JNDI | weblogic.jms.ConnectionFactory | weblogic.jms.XAConnectionFactory |
| Connection 類型 | javax.jms.Connection | javax.jms.XAConnection |
| Session 類型 | Session (createSession) | XASession (createXASession) |
| 事務邊界 | Session 內部 commit/rollback | UserTransaction (JTA) 控制 |
oracle.jdbc.xa.client.OracleXADataSource),否則資料庫操作也無法納入全域事務。總結:JTA 全域事務生效的前提是所有參與資源(JMS、DB 等)均使用 XA 驅動與 XA 連線,否則事務邊界將退化為本地事務,導致跨資源一致性失效。