EJB技術(shù)的數(shù)據(jù)庫(kù)應(yīng)用
本文介紹時(shí)EJB數(shù)據(jù)庫(kù)的入門知識(shí),旨在介紹EJB數(shù)據(jù)庫(kù)應(yīng)用及數(shù)據(jù)庫(kù)編程主要要求。讓大家對(duì)EJB技術(shù)的數(shù)據(jù)庫(kù)應(yīng)用有一個(gè)初步的認(rèn)識(shí),為以后更好的學(xué)習(xí)EJB技術(shù)的數(shù)據(jù)庫(kù)應(yīng)用知識(shí)打下堅(jiān)實(shí)的基礎(chǔ)。
一、J2EE 技術(shù)簡(jiǎn)介
J2EE是 SUN 公司提出的在分布式環(huán)境中的一種體系結(jié)構(gòu),它提供了一種基于組件的設(shè)計(jì)、開(kāi)發(fā)、集成、部署企業(yè)應(yīng)用系統(tǒng)的方法,J2EE平臺(tái)提供了多層分布式的應(yīng)用系統(tǒng)模型、重用組件的能力、統(tǒng)一的安全模型和靈活的事務(wù)控制。基于組件的J2EE企業(yè)應(yīng)用系統(tǒng)具有平臺(tái)獨(dú)立性,所以不受任何軟件產(chǎn)品和任何軟件廠家API的約束?!?/p>
J2EE定義了下面的組件:
- application client 和 applets 是客戶層組件;
- Java Servlet 和 JSP 組件是WEB 層組件;
- Enterprise JavaBean(EJB) 組件是業(yè)務(wù)處理層組件。
EJB 技術(shù)是J2EE 體系一部分,EJB 組件是用 Java 語(yǔ)言編寫的,是可以被客戶端程序存取的可重用的服務(wù)器端組件,它運(yùn)行在J2EE 服務(wù)器上,在客戶/服務(wù)器系統(tǒng)中,EJB 提供類似于中間件的服務(wù)。
J2EE 服務(wù)器提供應(yīng)用系統(tǒng)系統(tǒng)級(jí)的服務(wù),像事務(wù)管理、安全管理、數(shù)據(jù)庫(kù)存取等,開(kāi)發(fā)人員不必自己開(kāi)發(fā)系統(tǒng)級(jí)服務(wù),所以可以集中精力開(kāi)發(fā)應(yīng)用系統(tǒng)中的業(yè)務(wù)邏輯處理;用EJB 組件處理業(yè)務(wù)邏輯。
二、EJB 組件簡(jiǎn)介
EJB 組件分為兩類:Sesson bean 和 Entity bean
Sesson bean 代表 J2EE 服務(wù)器的客戶端,客戶端通過(guò)調(diào)用 Sesson bean 的功能和J2EE 服務(wù)器通信,Sesson bean 和客戶會(huì)話,可以認(rèn)為是客戶端的擴(kuò)展,例如:網(wǎng)上帳務(wù)系統(tǒng)的客戶可以調(diào)用 Sesson bean 的"輸入存款單"的功能來(lái)存入現(xiàn)金等。每一個(gè)Sesson bean 只能有一個(gè)客戶,當(dāng)客戶終止時(shí),與之相應(yīng)的Sesson bean 也終止。因此Sesson bean 是暫時(shí)的,不可持久的。
Entity bean 代表業(yè)務(wù)處理對(duì)象,它存儲(chǔ)在持久的存貯機(jī)制如數(shù)據(jù)庫(kù)中,例如,一個(gè)Entity bean 代表一個(gè)帳戶存單,它是存儲(chǔ)在關(guān)系數(shù)據(jù)庫(kù)中存單表的一行。Entity bean 的信息不一定存儲(chǔ)在關(guān)系數(shù)據(jù)庫(kù)中,它也可以存儲(chǔ)在對(duì)象數(shù)據(jù)庫(kù)中、文件中或其他別的存儲(chǔ)機(jī)制中( 本例子中用關(guān)系數(shù)據(jù)庫(kù))。
Entity bean 可以被多個(gè)客戶端共享。由于多個(gè)客戶端可能改變相同的數(shù)據(jù),所以Entity bean 在事務(wù)管理下工作是很重要的。通常情況下,EJB 容器提供事務(wù)管理。開(kāi)發(fā)人員可以在組件的部署描述文件中指定事務(wù)的屬性。每一個(gè)Entity bean 都有一個(gè)唯一的對(duì)象標(biāo)識(shí)符,也叫主鍵,這個(gè)主鍵可以讓客戶端定位一個(gè)Entity bean。
Entity bean 的持久性可以被 Entity bean 自己管理,也可以讓 EJB 容器管理,Entity bean自己管理要求開(kāi)發(fā)人員在Entity bean中提供數(shù)據(jù)存取代碼。例如客戶的Entity bean要調(diào)用 SQL 語(yǔ)句來(lái)通過(guò) JDBC 存取關(guān)系數(shù)據(jù)庫(kù)。EJB 容器管理Entity bean持久性意味著 EJB容器自動(dòng)處理數(shù)據(jù)存取的調(diào)用。
兩種類型的EJB 組件(Session bean 和 Entity beans)都可以存取數(shù)據(jù)庫(kù)。選擇哪一類 EJB 組件來(lái)存取數(shù)據(jù)庫(kù)依賴于具體的應(yīng)用系統(tǒng)。
下面的情況可以在 Session bean 組件中調(diào)用 SQL 語(yǔ)句來(lái)存取數(shù)據(jù)庫(kù):
- 應(yīng)用系統(tǒng)相對(duì)簡(jiǎn)單。
- SQL 語(yǔ)句返回的數(shù)據(jù)不能被多個(gè)客戶端共享使用。
- 數(shù)據(jù)不代表一個(gè)業(yè)務(wù)實(shí)體。
下面的情況要用Entity beans 組件:
- 超過(guò)一個(gè)客戶端使用數(shù)據(jù)庫(kù)調(diào)用返回的數(shù)據(jù)。
- 數(shù)據(jù)代表一個(gè)業(yè)務(wù)實(shí)體。
- 開(kāi)發(fā)者想從 Sesson bean 中隱藏關(guān)系模型。
EJB 結(jié)構(gòu)的這種靈活性可以讓開(kāi)發(fā)人員用不同的方法來(lái)開(kāi)發(fā)應(yīng)用系統(tǒng)。
#p#
三、建立數(shù)據(jù)庫(kù)連接
EJB 容器維護(hù)數(shù)據(jù)庫(kù)的連接池,這個(gè)連接池對(duì) EJB 組件來(lái)說(shuō)是透明的。當(dāng)EJB 組件申請(qǐng)一個(gè)連接時(shí),EJB 容器從連接池中提取一個(gè)連接并分配給組件。由于EJB 容器只是分配一個(gè)連接給 EJB 組件,所以組件很快就獲得這個(gè)連接并連接數(shù)據(jù)庫(kù)。數(shù)據(jù)庫(kù)調(diào)用之后,組件就可以釋放連接,這樣它又可以快速申請(qǐng)到另一個(gè)連接。又因?yàn)橐粋€(gè)組件只占用這個(gè)連接很短的時(shí)間,從而同一個(gè)連接可以被多個(gè)組件使用。
組件不是通過(guò)數(shù)據(jù)庫(kù)的絕對(duì)名來(lái)連接數(shù)據(jù)庫(kù),而是用邏輯名連接到數(shù)據(jù)庫(kù), 即用 JNDI lookup 來(lái)獲得數(shù)據(jù)庫(kù)連接,例如:在下面例子中的AccountEJB 類中,連接數(shù)據(jù)庫(kù)有以下幾個(gè)步驟:
1、指定數(shù)據(jù)庫(kù)的邏輯名:
private String dbName = "java:comp/env/jdbc/AccountDB";
2、獲得數(shù)據(jù)源:
InitialContext ic = new InitialContext();
DataSource ds = (DataSource) ic.lookup(dbName);
3、從數(shù)據(jù)源得到數(shù)據(jù)庫(kù)連接:
Connection con = ds.getConnection();
這種間接的連接數(shù)據(jù)庫(kù)有以下幾個(gè)優(yōu)點(diǎn):
- 可以在具有不同的數(shù)據(jù)庫(kù)名的不同環(huán)境中部署相同的 EJB 組件。
- 可以在多個(gè)應(yīng)用中重用EJB 組件。
- 可以集成 EJB 組件到運(yùn)行在分布環(huán)境的應(yīng)用系統(tǒng)中。
另外,EJB 規(guī)范沒(méi)有要求 J2EE的實(shí)現(xiàn)支持某一個(gè)特別類型的數(shù)據(jù)庫(kù)系統(tǒng),因此EJB 組件可以連接到不同的數(shù)據(jù)庫(kù)系統(tǒng)。四、EJB 數(shù)據(jù)庫(kù)應(yīng)用的例子
下面以一個(gè)簡(jiǎn)單的例子 "銀行帳戶"應(yīng)用系統(tǒng)來(lái)介紹 EJB 組件的Entity bean類型的組件存取數(shù)據(jù)庫(kù)。
Entity bean 的狀態(tài)存儲(chǔ)在關(guān)系數(shù)據(jù)庫(kù)的 ACCOUNT 表中,表ACCOUNT 由下面的SQL 語(yǔ)句創(chuàng)建:
CREATE TABLE ACCOUNT
?。╥d VARCHAR(3) CONSTRAINT pk_account PRIMARY KEY,
firstname VARCHAR(24),
lastname VARCHAR(24),
balance DECIMAL(10.2));
和其他EJB 組件一樣,開(kāi)發(fā)人員必須編寫 Entity bean 的 Entity Bean Class 代碼(AccountEJB.java)、Home Interface 代碼(AccountHome.java)及Remote Interface 代碼(Account.java)。
Entity Bean Class 代碼( AccountEJB.java)
EntityBean 接口方法
EjbCreate 方法:當(dāng)客戶端調(diào)用 create 方法時(shí),EJB 容器調(diào)用相應(yīng)的ejbCreate 方法。一個(gè)Entity組件的ejbCreate 方法要實(shí)現(xiàn)下列工作:
- 插入Entity Bean 的狀態(tài)到數(shù)據(jù)庫(kù)中
- 初始化實(shí)例變量
- 返回主鍵。
AccountEJB的ejbCreate 方法調(diào)用insertRow 方法,而insertRow 方法發(fā)出一個(gè) insert SQL 語(yǔ)句插入Entity Bean 的狀態(tài)到數(shù)據(jù)庫(kù)中,下面是 Account 類中ejbCreate 方法的源代碼:
sublic String ejbCreate (String id,String firstName,String lastName,double balance)throw CreateException{
if (balance < 0.00)
{
throw new CreateException("A negative initial balance is not allowed."); }
try {
insertRow(id,firstName,lastName,balance);
} catch (Exception ex) {
throw new EJBException("ejbCreate:"+ex.getMessage()); } this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.balance = balance;
return id; }
throws 子句可以包含 javax.ejb.CreateException 和別的應(yīng)用系統(tǒng)中指定的例外處理例程(exceptions)。Entity Bean的狀態(tài)也可以通過(guò)非 J2EE 應(yīng)用系統(tǒng)直接插入到數(shù)據(jù)庫(kù)中,如SQL 語(yǔ)言腳本插入一行數(shù)據(jù)到 ACCOUNT表中,盡管這條數(shù)據(jù)不是通過(guò) ejbCreate 方法插入到數(shù)據(jù)庫(kù)中的,但Entity Bean 同樣能通過(guò)客戶端程序定位這條數(shù)據(jù)。
ejbPostCreate 方法
對(duì)于每一個(gè)ejbCreate 方法,開(kāi)發(fā)人員必須在Entity Bean中寫一個(gè)ejbPostCreate 方法,EJB 容器在調(diào)用完ejbCreate 以后,就立即調(diào)用ejbPostCreate,和 ejbCreate 方法不一樣,ejbPostCreate 方法可以調(diào)用 getPrimaryKey 等方法,通常ejbPostCreate 方法是空的。
ejbRemove 方法
當(dāng)客戶端通過(guò)調(diào)用 remove 方法來(lái)刪除一個(gè) Entity Bean 的狀態(tài)數(shù)據(jù)時(shí),EJB 容器調(diào)用 ejbRemove 方法,ejbRemove 方法從數(shù)據(jù)庫(kù)中刪除一個(gè)Entity Bean 狀態(tài)數(shù)據(jù)。代碼如下:
public void ejbRemove() {
try {
deleteRow(id);
} catch (Exception ex){
throw new EJBException ex("ejbRemove:"+exgetmessage());
}
}
如果ejbRemove 方法遇到系統(tǒng)級(jí)錯(cuò)誤,將執(zhí)行javax.ejb.EJBException. 如果遇到應(yīng)用級(jí)錯(cuò)誤,將執(zhí)行javax.ejb.RemoveException。
entity bean 的狀態(tài)數(shù)據(jù)也可以通過(guò)數(shù)據(jù)庫(kù)的 delete 語(yǔ)句直接刪除數(shù)據(jù)。
EjbLoad 方法和 ejbStore 方法
EJB 容器需要維持 Entity Bean 的實(shí)例變量與數(shù)據(jù)庫(kù)中相應(yīng)值的同步,這需要調(diào)用 ejbLaod 方法和ejbStore 方法。ejbLoad 方法用數(shù)據(jù)庫(kù)中的數(shù)據(jù)刷新變量的值,ejbStore 方法把變量的值寫入到數(shù)據(jù)庫(kù)中??蛻舳瞬荒苷{(diào)用 ejbLoad 方法和ejbStore 方法。
如果業(yè)務(wù)處理的方法關(guān)系到事物處理,EJB 容器要在業(yè)務(wù)處理方法調(diào)用之前調(diào)用 ejbLoad 方法刷新數(shù)據(jù),業(yè)務(wù)處理方法執(zhí)行之后,EJB 容器又立即調(diào)用 ejbStore 方法把數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫(kù)中。因?yàn)?EJB 容器調(diào)用ejbLoad方法和ejbStore 方法,開(kāi)發(fā)人員在業(yè)務(wù)處理方法中不必刷新和存儲(chǔ)實(shí)例變量的值。
如果ejbLoad 方法和ejbStore 方法不能在低層數(shù)據(jù)庫(kù)中定位 Entity Bean,將執(zhí)行 javax.ejb.NoSuchEntityException。
在 AccountEJB 類中,ejbLoad 方法調(diào)用 loadRow 方法,loadRow 則發(fā)出一個(gè) select 語(yǔ)句從數(shù)據(jù)庫(kù)提取數(shù)據(jù)分配給實(shí)例變量;ejbStore 方法調(diào)用 storeRow 方法,storeRow 方法則用 update 語(yǔ)句把實(shí)例變量的值存儲(chǔ)到數(shù)據(jù)庫(kù)。代碼如下:
public void ejbLoad(){
try{
loadRow();
}catch (Exception ex){
throw new EJBException ("ejbLoad:"+ex.getMessage());
}
}
public void ejbStore(){
try{
storeRow();
}catch (Exception ex){
throw new EJBException ("ejbStore:"+ex.getMessage());
} }
Finder 方法 :
Finder 方法允許客戶端查找 entity bean ,AccountClient 中有三種方法查找entity bean:
Account jones = home.findByPrimaryKey("836");
Collection c home.findByLastName("Smith");
Collection c home.findInRange(20.00,99.00);
Entity bean 類必須實(shí)現(xiàn)相應(yīng)的方法,并且文件名以ejbFind 前綴開(kāi)始,如:AccountEJB 類實(shí)現(xiàn) ejbFindByLastName 的方法如下:
public Collection ejbFinfBylastName(String lastName)
throw FinderException {
Collection result;
Try {
Result = selectByLastName(lastName);
} catch (Exception ex) {
throw new EJBException("ejbFindByLastName" + ex.getMessage()); }
if (result.isEmpty()){
throw new ObjectNotFoundException("No row found.");
} else {
return result} }
應(yīng)用系統(tǒng)中特定的 finder,如 ejbFindByLastName 和ejbFindInRange,是可選的,但是必須含有 ejbFindByPrimaryKey 方法,ejbFindByPrimaryKey 方法用主鍵作參數(shù),用來(lái)定位一個(gè) entity bean 的狀態(tài)數(shù)據(jù),下面是 ejbFindByPrimaryKey 方法的代碼:
public String ejbFindByPrimaryKey(String primaryKey)
throws FinderException {
boolean result;
try {
result = selectByPrimaryKey(primaryKey);
} catch (Exception ex) {
throw new EJBException("ejbFindByPrimaryKey: " + ex.getMessage()); }
if (result) {
return primaryKey;
}
else {
throw new ObjectNotFoundException ("Row for id " + primaryKey + " not found.");
}
}
ejbFindByPrimaryKey 方法以 primaryKey 作為參數(shù)并返回它的值。
注意:
1.只有 EJB 容器可以調(diào)用ejbFindByPrimaryKey,而客戶端不能直接調(diào)用 ejbFindByPrimaryKey 方法,客戶端只能調(diào)用在 home 接口中定義的 findByPrimaryKey。
2.在 entity bean 類中開(kāi)發(fā)人員必須實(shí)現(xiàn)ejbFindByPrimaryKey 方法。
3.一個(gè) finder 方法的名字必須以 ejbFind 作為前綴。
4.返回值必須是主鍵或者是一個(gè)主鍵的集合。
throw 子句可以包含 javax.ejb.FinderException,和其他別的例外處理例程。如果一個(gè)finder 方法只要求返回唯一一個(gè)主鍵,如果主鍵不存在,則應(yīng)該執(zhí)行 javax.ejb.ObjectNotFoundException,ObjectNotFoundException 是FoundException的一個(gè)子類;如果 finder 方法要求返回的是一個(gè)主鍵的集合,則應(yīng)該執(zhí)行 FinderException 來(lái)處理。
業(yè)務(wù)處理方法
業(yè)務(wù)處理方法包含想在 Entity Bean 中實(shí)現(xiàn)的業(yè)務(wù)處理邏輯。通常業(yè)務(wù)處理方法不存取數(shù)據(jù)庫(kù),這允許開(kāi)發(fā)人員可以把業(yè)務(wù)處理邏輯從數(shù)據(jù)庫(kù)存取中獨(dú)立出來(lái)。
在 AccountEJB entity bean 中包含下面的業(yè)務(wù)處理方法:
public void debit(double amount)
throw InsufficientBalanceException {
if (balance - amount <0){
throw new InsufficientBalanceException();
}
balance -= amount;
}
public void credit (double amount) {
balance += amount;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public double getBalance() {
return balance;
}
AccountClient 程序中調(diào)用業(yè)務(wù)處理方法:
Account duke = home.create("123","Duke","Earl",0.00);
Duke.credit(88.50);
Duke.debit(20.25);
Double balance = duke.getBalance();
注意:
1、業(yè)務(wù)處理方法的名稱不能和 EJB 體系中定義的方法的名稱沖突,其他的要求和 entity bean 和 sesson bean 中其它方法的要求相同。
2、可以在throw 子句中包含應(yīng)用程序定義的例外處理例程,如 debit 方法執(zhí)行InsufficientBalanceException。為了識(shí)別系統(tǒng)級(jí)錯(cuò)誤,業(yè)務(wù)處理邏輯應(yīng)該調(diào)用 javax.ejb.EJBException。
#p#
下面是對(duì) AccountEJB 類中存取數(shù)據(jù)庫(kù)的總結(jié):
因?yàn)闃I(yè)務(wù)處理方法中不需要存取數(shù)據(jù)庫(kù),所以在 AccountEJB 類中的業(yè)務(wù)處理方法沒(méi)有存取數(shù)據(jù)庫(kù)。但業(yè)務(wù)處理方法可以通過(guò) EJB 容器調(diào)用 ejbStore 來(lái)修改實(shí)例變量。當(dāng)然開(kāi)發(fā)人員也可以在 AccountEJB 類的業(yè)務(wù)處理方法中存取數(shù)據(jù)庫(kù),這依賴于應(yīng)用程序的具體要求,在存取數(shù)據(jù)庫(kù)之前必須連接數(shù)據(jù)庫(kù)。
Home 接口(Interface)
在home 接口中定義讓客戶端創(chuàng)建和查找 entity bean 的方法。Account Home 接口如下:
import java.util.Collection;
import java.rmi.RemoteException;
import javax.ejb.*;
public interface AccountHome extends EJBHome {
public Account create(String id, String firstName, String lastName, double balance)
throws RemoteException, CreateException;
public Account findByPrimaryKey(String id)
throws FinderException, RemoteException;
public Collection findByLastName(String lastName)
throws FinderException, RemoteException;
public Collection findInRange(double low, double high)
throws FinderException, RemoteException;
}
在Home 接口中,每一種finder 方法必須和 entity bean 類中的 finder 方法對(duì)應(yīng);finder 方法的名稱必須以 find 開(kāi)始,就象 entity bean 類中的 finder 方法必須以 ejbFind 一樣,例如:AccountHome 類中定義的findByLastName 方法和AccountEJB 類中實(shí)現(xiàn)的 ejbFindByLastName 方法。
Remote 接口
Remote 接口定義客戶端可以調(diào)用的業(yè)務(wù)處理方法,Account remote 接口的代碼如下:
import javax.ejb.EJBObject;
import java.rmi.RemoteException;
public interface Account extends EJBObject {
public void debit(double amount)
throws InsufficientBalanceException, RemoteException;
public void credit(double amount)
throws RemoteException;
public String getFirstName()
throws RemoteException;
public String getLastName()
throws RemoteException;
public double getBalance()
throws RemoteException; }
以上就是我為大家介紹的EJB技術(shù)的數(shù)據(jù)庫(kù)應(yīng)用的基本知識(shí),希望這篇文章對(duì)大家有用,能夠有助于大家在EJB技術(shù)的數(shù)據(jù)庫(kù)應(yīng)用方面的提高。
【編輯推薦】