| 類型 | 通信 | 狀態 | 持久化 | 典型用途 |
| Message Driven (MDB) | 異步 (JMS) | 無 | 無 | 事件處理、異步任務 |
| Session Bean | 同步 | 有/無狀態 | 不持久化 | 業務流程控制 |
| Entity Bean | 同步 | 共享、主鍵、事務 | BMP / CMP | 領域數據建模 |
Entity Bean 兩種持久化模式
BMP (Bean Managed Persistence)
- 開發者手寫 JDBC/SQL 實現
ejbLoad/ejbStore/ejbFind 等
- 靈活性高,但代碼量大、移植性差、容易出錯
CMP (Container Managed Persistence) — 推薦
- 容器自動生成 SQL,字段映射通過部署描述符聲明
- 數據訪問邏輯與數據源解耦,跨應用服務器可移植
- 性能由容器優化 (延遲加載、預取、批量更新)
實戰:UserEJB 完整開發部署 (JBoss 3.0.2 + Hypersonic SQL)
1. 接口定義 (本地接口)
// LocalUser.java
public interface LocalUser extends EJBLocalObject {
String getUserID(); // PK
String getFullName(); void setFullName(String);
String getAddress(); void setAddress(String);
String getCity(); void setCity(String);
String getState(); void setState(String);
String getZip(); void setZip(String);
}
// LocalUserHome.java
public interface LocalUserHome extends EJBLocalHome {
LocalUser create(String userID, String fullName, String address, String city, String state, String zip) throws CreateException;
Collection findByFullName(String fullName) throws FinderException;
LocalUser findByPrimaryKey(String userID) throws FinderException;
}
2. Bean 類 (實現 EntityBean)
public class UserEJB implements EntityBean {
public String USERID, FULLNAME, ADDRESS, CITY, STATE, ZIP;
private EntityContext ctx;
// CMP 字段 getter/setter (容器調用)
public String getUserID() { return USERID; }
public void setUserID(String id) { USERID = id; }
// ... 其他字段同理
// 生命周期回調
public String ejbCreate(String userID, String fullName, String address, String city, String state, String zip) {
setUserID(userID); setFullName(fullName); setAddress(address); setCity(city); setState(state); setZip(zip);
return userID; // 返回主鍵
}
public void ejbPostCreate(...) {} // 無拋出 CreateException
public void setEntityContext(EntityContext ctx) { this.ctx = ctx; }
public void unsetEntityContext() { ctx = null; }
public void ejbActivate() {} public void ejbPassivate() {}
public void ejbLoad() {} public void ejbStore() {} public void ejbRemove() {}
}
3. 標準部署描述符 (ejb-jar.xml)
<entity>
<ejb-name>UserEJB</ejb-name>
<local-home>com.jeffhanson.datatier.ejb.LocalUserHome</local-home>
<local>com.jeffhanson.datatier.ejb.LocalUser</local>
<ejb-class>com.jeffhanson.datatier.ejb.UserEJB</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.String</prim-key-class>
<reentrant>False</reentrant>
<cmp-field><field-name>USERID</field-name></cmp-field>
<cmp-field><field-name>FULLNAME</field-name></cmp-field>
<cmp-field><field-name>ADDRESS</field-name></cmp-field>
<cmp-field><field-name>CITY</field-name></cmp-field>
<cmp-field><field-name>STATE</field-name></cmp-field>
<cmp-field><field-name>ZIP</field-name></cmp-field>
<primkey-field>USERID</primkey-field>
</entity>
<assembly-descriptor>
<container-transaction>
<method><ejb-name>UserEJB</ejb-name><method-name>*</method-name></method>
<trans-attribute>Required</trans-attribute>
</container-transaction>
</assembly-descriptor>
4. JBoss 特定映射 (jaws.xml)
<jaws>
<datasource>java:/DefaultDS</datasource>
<type-mapping>Hypersonic SQL</type-mapping>
<enterprise-beans>
<entity>
<ejb-name>UserEJB</ejb-name>
<create-table>true</create-table>
<table-name>UserEJB</table-name>
<cmp-field>
<field-name>USERID</field-name>
<column-name>USERID</column-name>
</cmp-field>
... 其他字段映射 ...
</entity>
</enterprise-beans>
</jaws>
5. 客戶端訪問 (UserService)
public class UserService {
private static LocalUserHome getHome() throws NamingException {
InitialContext ctx = new InitialContext();
return (LocalUserHome) ctx.lookup("local/UserEJB"); // 本地接口查找
}
public static UserInfo getUser(String userID) {
LocalUserHome home = getHome();
LocalUser user = home.findByPrimaryKey(userID);
if (user == null) user = home.create(userID, "John " + userID + " Doe", ...);
return convert(user);
}
public static UserInfo[] getUsersByState(String state) {
Collection list = getHome().findByState(state);
// 迭代轉換...
}
}
EJB QL:面向對象查詢語言
容器將 EJB QL 轉換為 SQL。在 jaws.xml 中定義查詢映射:
<query>
<query-method>
<method-name>findByState</method-name>
<method-params><method-param>java.lang.String</method-param></method-params>
</query-method>
<ejb-ql><![CDATA[
SELECT DISTINCT OBJECT(u) FROM UserEJB u WHERE u.STATE = ?1
]]></ejb-ql>
</query>
OBJECT(u):返回實體對象而非標量
?1:對應 findByState(String) 第一個參數
- 內置
findAll/findByPrimaryKey 無需定義
總結
EJB CMP 通過聲明式映射、容器生成 SQL、標準化 EJB QL,有效橋接對象與關係世界。在 JBoss 上配合 jaws.xml 完成數據源、表創建、字段映射配置,可快速構建可移植的持久化領域模型。合理使用 CMP 可大幅降低持久層開發複雜度,讓團隊聚焦業務邏輯。
- 上一篇文章: JBoss 3.2.6 實戰教程:從安裝到編寫部署第一個 HelloWorld EJB
- 下一篇文章: JBuilder 2005 開發 Spring 應用完整實戰:從 HelloWorld 到數據庫持久層
Copyright ©
程式碼之家 All Rights Reserved