1.1 什麼是Entity Bean
Entity Bean(實體Bean)是持久資料元件,代表存儲在外部媒體中的持久(Persistence)對象或者已有的企業應用系統資源。簡單地講,一個Entity Bean可以代表資料庫中的一行記錄,多個用戶端應用能夠以共享方式通路表示該資料庫記錄的Entity Bean。
那麼什麼是持久資料元件呢?為什麼要使用持久資料元件?了解了這兩個問題,也就清楚了Entity Bean的性質及用途。
持久資料元件指的是這樣一種對象,它們知道如何将自身放入持久存儲的空間中。它們使用一些持久機制,比如序列化、O/R映射。這種對象代表資料,例如使用持久資料元件代表下面這些資訊:
● 銀行帳号資訊,例如帳号、密碼和餘額;
● 員工資訊,例如姓名、部門和工資。
為什麼要把這些資料以對象的方式進行處理而不是直接處理資料庫中的原始資料,比如相關的記錄呢?答案是将資料視為對象是非常便利的,因為能夠友善地操作和管理對象,并且它們表現為一個緊湊的形式,此外,通過元件所在的應用伺服器,可以獲得事務、安全性等服務。
Entity Bean就是這種持久資料元件。Entity Bean知道怎樣在一個諸如資料庫的存儲空間中永久儲存自己。Entity Bean以域(field)的方式存儲資料,例如銀行帳号、密碼和餘額。依賴于EJB容器提供的事務服務,多個用戶端應用能夠在保持資料庫記錄的一緻性和完整性前提下實作對資料資源的共享。Entity Bean的生命期相對較長并且其狀态是持續的。隻要Entity Bean代表的資料庫記錄存在,該元件對象執行個體就一直存在,即使EJB容器崩潰,Entity Bean仍然具有生命力。
1.2 Entity Bean的子類型
按照Entity Bean持久性的實作形式,可以将Entity Bean分為容器管理持久性(CMP Container-Managed Persistence)群組件管理持久性(BMP Bean-Managed Persistence)兩種模型。在CMP類型EJB元件的實作代碼中,元件開發人員不需要為元件的持久性控制方法編寫任何資料庫操作的代碼,而是在元件組裝和部署過程中由部署工具自動建立;如果要建立BMP類型EJB元件,則元件程式設計人員需要為所有持久性方法編寫控制代碼。
1.3 Entity Bean的特點
與資料庫中的資料記錄相對應,每個實體類型EJB元件包含一個主鍵(Primary Key)辨別,該辨別與
元件代表的資料庫記錄主鍵相同。用戶端應用可以利用該主鍵定位EJB容器中的Entity Bean對象執行個體,進而定位元件代表的資料庫記錄。
實體類型EJB元件的主要特點包括:
● Entity Bean提供資料庫中記錄的視圖;
● Entity Bean具有無限制生命期,EJB伺服器崩潰也不會影響Entity Bean的存在;
● 多個Entity Bean可以對應同一資料庫記錄;
● EJB伺服器可以利用Entity Bean的passivate方法将Entity Bean緩存到臨時存儲空間中,同樣可以利用activate方法将緩存的Entity Bean重新讀入EJB容器并恢複元件對象執行個體;
● 用戶端應用可以利用在Entity Bean的Home接口中定義的建立、删除和查詢等方法對元件進行管理。
使用EJB QL開發查詢
2.1 什麼是EJB QL
在關系資料庫的操作中查詢是經常使用的,主要是通過select語句完成的。Entity Bean作為代表資料庫中資料的持久性元件也同樣需要查詢操作,即能夠找到符合某一查詢條件的Entity Bean的執行個體。Entity Bean的查詢操作是通過定義finder()方法完成的。對于CMP,定義finder()方法僅僅是聲明一個方法,指明finder()方法的參數,該參數通常與查詢條件中的參數對應,真正完成查詢的動作是由EJB容
器完成的。EJB容器要讀取部署描述檔案ejb-jar.xml(在*.jar/META-INF裡)中的<query>項,該項包含了與finder()方法相對應的查詢語句。<query>項中的查詢語句遵循的文法規範是EJB QL。
EJB QL的開發查詢步驟如下:
1> 在Home接口中增加finder()方法,其參數為查詢條件中用到的參數;
2> 在ejb-jar.xml檔案的<query>項定義EJB QL語句。
EJB QL是EJB2.0新加入的特性,它實作了如何在Home接口中定義各種查找方法。它以SQL-92為基礎,可以由容器自動編譯,這使得Entity Bean具有更高的可移植性,并且容易部署。
EJB QL語句由select、where、orderby三個子句組成,其後兩個子句是可選的。
EJB QL查詢語句舉例如下:
例1:
SELECT stu FROM Student AS stu WHERE stu.grade > 5
該查詢語句的含義是查詢grade>5的Student Bean執行個體。“Student”是抽象模式名(Abstract schema name),在ejb-jar.xml檔案中<abstract schema name>項指定的名稱。“stu”是Student的别名,引入别名的好處是可以引用所代表對象的字段。stu.grade表示Student的grade字段,稱為路徑表達式。
例2:
SELECT i FROM Student As i WHERE i.name = ?1
該查詢語句的含義是查找名字與finder()方法中的第一個參數相同的Student Bean執行個體。
WHERE字句的使用說明:
★ 以?n代表相應的finder()方法的輸入參數;
★ 字元串類型的值要用單引号括起來(如果值中有單引号,則用雙引号代替)
WHERE語句中可以使用的表達式和運算符如下:
☆ +,-,*,/,=,<,<=,>=,>,<>,NOT,AND,OR
☆ between
☆ like
☆ in
☆ member of
☆ is null(is not null)
内置函數:
● CONCAT(String first,String second)
● SUBSTRING(String source,int start,int length)
● LOCATE(String source,String patter)
● LENGTH(String source)
實體Bean的BMP和CMP選擇
EJB有兩種主要類型BMP(Bean managed persistence )和CMP(Container managed persistence ),這兩種類型各有優缺點。
BMP是在Bean中完成對資料庫JDBC的各種調用,也就是說,在你的實體bean(entity bean)中,明确寫入了SQL語句,如"insert .. "或"select ..",并且使用Datasource獲得一個資料庫資源以及連接配接(connection)進而對資料庫直接進行增加 删除修改。
CMP是由EJB容器自動完成對資料庫的操作,你所有做的,就是在實體bean重寫入SetXXX或getXXX方法,然後在ejb-jar.xml中定義cmp-field就可以。很明顯,CMP編寫要簡單多,而且資料庫操作由EJB容器完成應該是一種趨勢,但是CMP有個缺點就是不夠靈活,如果我們要完成類似SQL搜尋語句的like指令,如"select * from A where name like '%banqiao'",CMP就無法自動幫助我們完成,這樣我們就需要BMP自己來寫。
在實際應用,一般為了效率考慮,我們盡量使用CMP,但如何為将來有可能使用BMP作好準備,就是說有可以延伸到BMP的基礎。EJB 2.0對CMP的抽象類支援為我們提供了這種實作的基礎。
總體思路是,先使用抽象類完成CMP 如果需要BMP 可以extend這個抽象類,然後覆寫原來的方法(用自己的特殊SQL語句操作來覆寫該方法)。
以Java 寵物店(Java Pet Store Demo 1.3)中的位址實體bean:AddressEJB為例:
public abstract class AddressEJB implements EntityBean {
private EntityContext context = null;
// getters and setters for PO CMP fields
public abstract String getFirstName();
public abstract void setFirstName(String name);
public abstract String getLastName();
public abstract void setLastName(String name);
public abstract String getStreet1();
public abstract void setStreet1(String name);
public abstract String getStreet2();
public abstract void setStreet2(String name);
public abstract String getCity();
public abstract void setCity(String name);
public abstract String getState();
public abstract void setState(String name);
public abstract String getCountry();
public abstract void setCountry(String name);
public abstract String getZip();
public abstract void setZip(String name);
public Object ejbCreate(String fName, String lName, String s1,
String s2, String cy, String st,
String cnty, String pcode)
throws CreateException {
setFirstName(fName);
setLastName(lName);
setStreet1(s1);
setStreet2(s2);
setCity(cy);
setState(st);
setCountry(cnty);
setZip(pcode);
return null;
}
public void ejbPostCreate(String fName, String lName, String street1,
String street2, String city, String state,
String country, String zip)
throws CreateException{}
public void setEntityContext(EntityContext c){ context = c; }
public void unsetEntityContext(){}
public void ejbRemove() throws RemoveException {}
public void ejbActivate() {}
public void ejbPassivate() {}
public void ejbStore() {}
public void ejbLoad() {}
在上面的AddressEJB中,我們看到隻有setXXX或getXXX的方法。
在相應的部署描述檔案ejb-jar.xml中我們看到:
<entity>
<display-name>AddressEJB</display-name>
<ejb-name>AddressEJB</ejb-name>
<local-home>com.sun.j2ee.blueprints.address.ejb.AddressLocalHome</local-home>
<local>com.sun.j2ee.blueprints.address.ejb.AddressLocal</local>
<ejb-class>com.sun.j2ee.blueprints.address.ejb.AddressEJB</ejb-class>
<persistence-type>Container</persistence-type>
<prim-key-class>java.lang.Object</prim-key-class>
<reentrant>False</reentrant>
<cmp-version>2.x</cmp-version>
<abstract-schema-name>Address</abstract-schema-name>
<cmp-field>
<field-name>firstName</field-name>
</cmp-field>
<field-name>lastName</field-name>
<field-name>street1</field-name>
<field-name>street2</field-name>
<field-name>city</field-name>
<field-name>state</field-name>
<field-name>country</field-name>
<field-name>zip</field-name>
<security-identity>
<description></description>
<use-caller-identity></use-caller-identity>
</security-identity>
</entity>
在上面部署檔案中,标明了Address資料庫字段:
firstName,lastName,street1,street2,city,state,country,zip
一旦我們要使用BMP, 隻要繼承上面的CMP bean:
public class AddressBeanBMP extends AddressEJB {
用我們自己的BMP方法覆寫AddressEJB中的方法:
ejbLoad() -->從資料庫中擷取資料(SELECT)
ejbStore() -->修改資料庫資料UPDATE)
ejbRemove() -->删除資料庫資料(DELETE)
ejbCreate() -->插入新的資料記錄(INSERT)
ejbFindByPrimaryKey(primary key) --> 確定 primary key 存在.
ejbFindAllPrimaryKey() -->自己的定義 傳回一個primary key所有資料記錄的collectionxiam
下面以ejbCreate()為例:
String cnty, String pcode) throws CreateException {
// insert row into database
this.fName = fName;
this.lName = lName;
this.s1 = s1;
this.s2 = s2;
this.cy=cy;
this.st=st;
this.cnty=cnty;
this.pcode=pcode;
// Insert database record
try {
Connection connection = getConnection();
PreparedStatement statement = connection.prepareStatement
("INSERT INTO Address (firstName,lastName,street1,street2,city,state,country,zip) VALUES
(?, ?, ?,?,?,?)");
statement.setString(1, fName);
statement.setString(2, lName);
statement.setString(3, pcode);
statement.setString(4, s1);
statement.setString(5, s2);
statement.setString(6, st);
statement.setString(7, cy);
statement.setString(8, cnty);
if (statement.executeUpdate() != 1) {
statement.close();
connection.close();
throw new CreateException("Could not create: " );
catch(SQLException e) {
throw new EJBException("Could not create: " );