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

EJB 回傳值解決方案:Vector 與 RowSet (CachedRowSet) 實戰比較

     編輯:Java 相關知識

許多開發者對 EJB 回傳值感到困惑。本文提供兩種實用解決方案:傳統 Vector 與現代 RowSet(特別是 CachedRowSet),並附完整程式碼範例。

方案一:使用 Vector 回傳主鍵集合

適用於尋找器方法回傳主鍵枚舉:

public Enumeration ejbFindBigAccounts(double balanceGreaterThan) {
    log("ejbFindBigAccounts (balance > " + balanceGreaterThan + ")");
    Connection con = null;
    PreparedStatement ps = null;
    try {
        con = getConnection();
        ps = con.prepareStatement("select id from ejbAccounts where bal > ?");
        ps.setDouble(1, balanceGreaterThan);
        ps.executeQuery();
        ResultSet rs = ps.getResultSet();
        Vector v = new Vector();
        String pk;
        while (rs.next()) {
            pk = rs.getString(1);
            v.addElement(pk);
        }
        return v.elements();
    } catch (SQLException sqe) {
        log("SQLException: " + sqe);
        throw new EJBException(sqe);
    } finally {
        cleanup(con, ps);
    }
}

結論:不夠優雅、使用不便。需手動迭代 ResultSet、填充 Vector、回傳 Enumeration,客戶端再迭代取值,類型安全性差。

方案二:使用 RowSet (CachedRowSet) 回傳可序列化、可斷線操作的資料集

RowSet 為介面,需實作類別。Sun 規範提供三個實作:CachedRowSet、JdbcRowSet、WebRowSet。JDK 1.4 與 J2EE 1.2 雖含 RowSet 介面,但無三實作類別,一般開發工具(如 WSAD)同樣缺失,需下載 JDBC 2.0 Optional Package:

https://developer.java.sun.com/developer/earlyAccess/crs/

安裝步驟(以 WSAD 為例)

  1. 解壓縮取得 rowset.jar,放置任意位置(如 d:\jdk1.4\jre\rowset.jar)
  2. 開發工具中增加類別路徑變數:ROWSET_PATH 對應 d:\jdk1.4\jre\rowset.jar
  3. 專案屬性中加入 rowset_path
  4. 原始碼匯入:import sun.jdbc.rowset.*;

CachedRowSet 真的是好東西,類似 MS ADO Recordset 與 Borland TClientDataSet,最大優勢在 快取功能——斷線操作資料,重連時批次更新回資料庫。

完整範例:Coffees 應用(伺服器端 Session Bean + 客戶端)

伺服器端:CoffeesBean

package example4;
import java.sql.*;
import javax.sql.*;
import sun.jdbc.rowset.*;
import javax.naming.*;
import javax.ejb.*;

public class CoffeesBean implements SessionBean {
    private SessionContext sc = null;
    private Context ctx = null;
    private DataSource ds = null;

    public CoffeesBean() {}
    public void ejbCreate() throws CreateException {
        try {
            ctx = new InitialContext();
            ds = (DataSource) ctx.lookup("jdbc/CoffeesDB");
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new CreateException();
        }
    }

    public RowSet getCoffees() throws SQLException {
        Connection con = null;
        ResultSet rs;
        CachedRowSet crs;
        try {
            con = ds.getConnection("webCustomer", "webPassword");
            Statement stmt = con.createStatement();
            rs = stmt.executeQuery("select * from coffees");
            crs = new CachedRowSet();
            crs.populate(rs);
            crs.setTableName("coffees"); // JDBC 驅動不提供此中繼資料
            rs.close();
            stmt.close();
        } finally {
            if (con != null) con.close();
        }
        return crs; // 注意:原文變數名為 rset,此處修正為 crs
    }

    public void updateCoffees(RowSet rs) throws SQLException {
        Connection con = null;
        try {
            CachedRowSet crs = (CachedRowSet) rs;
            con = ds.getConnection("webCustomer", "webPassword");
            crs.acceptChanges(con); // 將變更寫回資料庫
        } finally {
            if (con != null) con.close();
        }
    }

    // SessionBean 介面方法
    public void setSessionContext(SessionContext sc) { this.sc = sc; }
    public void ejbRemove() {}
    public void ejbPassivate() {}
    public void ejbActivate() {}
}

客戶端:CoffeesClient

package example4;
import java.sql.*;
import javax.sql.*;
import sun.jdbc.rowset.*;
import javax.naming.*;
import javax.ejb.*;
import javax.rmi.*;

class CoffeesClient {
    public static void main(String[] args) {
        try {
            // 初始化 Bean
            Context ctx = new InitialContext();
            Object obj = ctx.lookup("ejb/Coffees");
            CoffeesHome coffeesHome = (CoffeesHome)
                PortableRemoteObject.narrow(obj, CoffeesHome.class);
            Coffees coffees = coffeesHome.create();

            // 從 Bean 取得 RowSet
            CachedRowSet rset = (CachedRowSet) coffees.getCoffees();

            // 找到 Columbian 咖啡,價格漲 10%
            while (rset.next()) {
                String coffeeName = rset.getString("COF_NAME");
                if (coffeeName.equalsIgnoreCase("Columbian")) {
                    rset.updateFloat("PRICE",
                        (float)(rset.getFloat("PRICE") * 1.10));
                    rset.updateRow();
                }
            }

            // 送回 Bean 更新資料庫
            System.out.println("Calling update method");
            coffees.updateCoffees((RowSet) rset);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

關鍵優勢總結

  • 斷線操作:客戶端離線修改 CachedRowSet,稍後一次性 acceptChanges() 寫回
  • 類型安全:getString()、updateFloat() 等強型別存取
  • 可捲動/可更新:支援雙向游標與資料修改
  • 元資料管理:setTableName() 協助寫回操作
  • 標準化:javax.sql.RowSet 為標準介面,未來可遷移至標準實作

範例簡單明瞭,CachedRowSet 讓 EJB 資料傳輸更靈活強大。Cheers! — Robin

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved