首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Apache Geronimo EJB 事務選項權衡 (二):Bean 管理事務 (BMT) 完整實作指南

     編輯:Java 相關知識

系列第二部分深入剖析 Bean 管理事務 (BMT):JTA 與 JDBC 兩種實作模式、回滾規則、禁止方法、Geronimo (OpenEJB) 部署描述符與 XDoclet 設定完整示範。

一、BMT 核心特徵

  • 開發者以程式碼控制事務邊界:begin()、commit()、rollback()
  • 支援 Session Bean、Message-Driven Bean (MDB),**Entity Bean 不支援** (容器管理持久化)
  • 同一 Bean 實例可連續執行多個事務,**不支援巢狀事務** (嘗試拋出異常)
  • 兩種實作:JTA 事務 (跨資源)、**JDBC 事務** (單資源、舊代碼遷移)

二、JTA 事務實作 (標準、跨資源)

核心 API:javax.transaction.UserTransaction

取得 UserTransaction 參考


// 方式一:從 EJBContext (Session Bean)
UserTransaction utx = ejbContext.getUserTransaction();

// 方式二:從 MessageDrivenContext (MDB)
UserTransaction utx = mdc.getUserTransaction();

// 方式三:JNDI 查找 (通用)
Context ctx = new InitialContext();
UserTransaction utx = (UserTransaction) ctx.lookup("java:comp/UserTransaction");

完整範例:跨兩資料庫更新


public class MySessionEJB implements SessionBean {
    private EJBContext ejbContext;

    public void updateTwoDatabases(...) {
        DataSource ds1 = null, ds2 = null;
        Connection conn1 = null, conn2 = null;
        PreparedStatement stmt1 = null, stmt2 = null;
        UserTransaction utx = null;
        
        try {
            InitialContext ic = new InitialContext();
            // 取得資料源與連線
            ds1 = (DataSource) ic.lookup("java:comp/env/jdbc/dbOneDS");
            conn1 = ds1.getConnection();
            stmt1 = conn1.prepareStatement(sql1);
            
            ds2 = (DataSource) ic.lookup("java:comp/env/jdbc/dbTwoDS");
            conn2 = ds2.getConnection();
            stmt2 = conn2.prepareStatement(sql2);
            
            // 事務控制
            utx = ejbContext.getUserTransaction();
            utx.begin(); // 開始事務
            
            stmt1.executeUpdate();
            stmt2.executeUpdate();
            
            utx.commit(); // 提交
            
        } catch (Exception e) {
            try { if (utx != null) utx.rollback(); } 
            catch (SystemException se) { 
                throw new EJBException("Rollback failed: " + se.getMessage()); 
            }
            throw new EJBException("Transaction failed: " + e.getMessage());
        } finally {
            // 關閉資源 (略)
        }
    }
    
    public void setSessionContext(SessionContext ctx) { this.ejbContext = ctx; }
    // 其他 EJB 生命週期方法...
}

三、JDBC 事務實作 (舊代碼遷移專用)

直接操作 java.sql.Connection,由資料庫事務管理器控制,非 EJB 容器。


public void updateFirstName(int customerId, String firstName) {
    Connection con = null;
    try {
        con = getConnection(); // 取得 JDBC 連線
        con.setAutoCommit(false); // 關閉自動提交
        
        String sql = "UPDATE customer SET firstName = ? WHERE customerId = ?";
        PreparedStatement ps = con.prepareStatement(sql);
        ps.setString(1, firstName);
        ps.setInt(2, customerId);
        ps.executeUpdate();
        
        con.commit(); // 提交
    } catch (Exception ex) {
        try { 
            if (con != null) con.rollback(); 
        } catch (SQLException sqx) {
            throw new EJBException("Rollback failed: " + sqx.getMessage());
        }
        throw new EJBException("Update failed: " + ex.getMessage());
    } finally {
        // 關閉連線...
    }
}

適用場景: 必須重用現有 JDBC 代碼。新開發優先用 JTA。

四、事務提交/回滾規則 (依 Bean 類型)

方法用途
begin()啟動新事務,關聯當前執行緒
commit()提交當前執行緒關聯事務
rollback()強制回滾當前事務
setRollbackOnly()標記僅能回滾
setTransactionTimeout(seconds)設定超時秒數
getStatus()取得事務狀態

關鍵差異: JTA 事務跨連線開關保持事務上下文;JDBC 事務隨連線關閉而結束。

五、BMT 中禁止呼叫的方法

  • java.sql.Connection.commit()、rollback()、setAutoCommit() (JTA 模式下)
  • javax.jms.Session.commit()、rollback()
  • EJBContext.getRollbackOnly()、setRollbackOnly() (CMT 專用)
  • UserTransaction 以外的任何事務管理 API

替代方案:

  • 事務狀態:utx.getStatus()
  • 標記回滾:utx.setRollbackOnly()
  • 回滾:utx.rollback()

六、Geronimo (OpenEJB) 部署設定

ejb-jar.xml 關鍵元素:



    SampleSession
    ...
    Bean 

XDoclet 設定 (建議方式)


/**
 * @ejb.bean 
 *   name="SampleSession"
 *   type="Stateless"
 *   transaction-type="Bean"  
 *   ...
 */
public abstract class SampleSessionBean implements SessionBean { ... }

生成的 ejb-jar.xml 將包含 <transaction-type>Bean</transaction-type>。

注意區別:

  • CMT 方法屬性:@ejb.transaction type="Required"
  • BMT Bean 屬性:@ejb.bean transaction-type="Bean"

七、結語

BMT 賦予開發者事務邊界完全控制權,JTA 模式支援跨資源分布式事務,JDBC 模式服務遷移舊代碼。Geronimo/OpenEJB 透過 transaction-type="Bean" 宣告啟用 BMT。關鍵在於:遵守 Bean 類型的提交/回滾規則、避免呼叫禁止 API、正確處理異常回滾路徑。下一部分將綜合 CMT 與 BMT 進階選項。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
Bean 類型規則違規後果
Stateless Session Bean業務方法返回前必須 commit/rollback容器回滾並拋出異常
Stateful Session Bean可跨多個客戶端調用,不必單一方法結束容器等待 Bean 結束事務
Message-Driven BeanonMessage() 或 ejbTimeout() 返回前必須 commit容器回滾並拋出異常