免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
EJB/CMP的開發(fā)例子,有詳細(xì)說明,比較好理解
作者:自由的豬 制作整理:左岸網(wǎng)絡(luò)http://www.leftworld.net
第6章 CMP的例子
Dale Green 著
Iceshape Zeng 譯
CMP實(shí)體Bean技術(shù)給開發(fā)者帶來了很多重要的好處。首先,EJB容器處理了所有數(shù)據(jù)庫(kù)的訪問操作。其次,容器管理了實(shí)體Bean之間的關(guān)系。因?yàn)檫@些服務(wù),你不需要為數(shù)據(jù)庫(kù)訪問而編寫任何代碼,而只用在部署描述符里指定配置。這種方法不僅可以節(jié)省開發(fā)者的時(shí)間,更重要的是它使企業(yè)Bean在訪問不同的數(shù)據(jù)庫(kù)時(shí)有更好的可移植性。
本章將重點(diǎn)介紹CMP實(shí)現(xiàn)的實(shí)體Bean應(yīng)用程序RosterApp這個(gè)例子的代碼和部署描述符設(shè)置。如果你對(duì)本章提到的術(shù)語和概念不太熟悉,請(qǐng)參考第4章企業(yè)Bean的CMP部分。
本章內(nèi)容:
RosterApp應(yīng)用概述
PlayerEJB代碼分析
實(shí)體Bean類
Local Home接口
Local接口
RosterApp設(shè)置說明
RoseterApp應(yīng)用程序設(shè)置
RosterClient客戶端設(shè)置
RosterJAR設(shè)置
TeamJAR設(shè)置
RosterApp中的方法調(diào)用
創(chuàng)建一個(gè)Player實(shí)體
將Player加入一個(gè)Team實(shí)體
刪除一個(gè)Player
從Team中刪除一個(gè)Player
查詢一個(gè)Team中所有的Player
得到Team中所有Player的副本
查詢特定位置的Player
查詢一個(gè)Player參加的Sports
運(yùn)行RosterApp應(yīng)用程序
啟動(dòng)用到的程序
部署
運(yùn)行客戶端
用deploytool工具部署CMP實(shí)現(xiàn)的實(shí)體Bean
指定企業(yè)Bean類型
選擇持久性字段和抽象模式名
為查找方法和Select方法編寫EJB QL查詢
生成SQL語句和指定表創(chuàng)建機(jī)制
設(shè)置數(shù)據(jù)庫(kù)的JNDI名,用戶名和密碼
定義關(guān)系
CMP主鍵
主鍵類
實(shí)體Bean的主鍵
產(chǎn)生主鍵值
一、RosterApp應(yīng)用概述
RosterApp應(yīng)用程序維護(hù)運(yùn)動(dòng)社團(tuán)中運(yùn)動(dòng)員分組的花名冊(cè)。它有五個(gè)組成部分,RosterAppClient是通過Remote接口訪問會(huì)話Bean RosterEJB的J2EE客戶端,RosterEJB通過Local接口訪問三個(gè)實(shí)體Bean:PlayerEJB,TeamEJB和LeagueEJB。
這些實(shí)體Bean用容器管理的持久性和關(guān)系。TeamEJB和PlayerEJB之間是雙向的多對(duì)多關(guān)系。雙向關(guān)系中每一個(gè)Bean都有一個(gè)關(guān)系字段來確定相關(guān)聯(lián)另一個(gè)Bean實(shí)例。多對(duì)多關(guān)系是指:可以參加多個(gè)運(yùn)動(dòng)項(xiàng)目的運(yùn)動(dòng)員(Player)可以加入多個(gè)組(team),而每個(gè)組又有多個(gè)運(yùn)動(dòng)員。LeagueEJB和TeamEJB之間是一對(duì)多的雙向關(guān)系:一個(gè)社團(tuán)可以有多個(gè)組,而一個(gè)組只能屬于一個(gè)社團(tuán)。
圖6-1描述了該應(yīng)用程序各組件和它們之間的關(guān)系。虛線箭頭表示通過調(diào)用JNDI lookup方法的訪問。
圖 6-1 RosterApp應(yīng)用程序
二、layerEJB代碼分析
PlayerEJB表示運(yùn)動(dòng)社團(tuán)中的運(yùn)動(dòng)員實(shí)體。本例中,它需要以下三各個(gè)類:
1. 實(shí)體Bean類(PlayerBean)
2. Local Home接口(LocalPlayerHome)
3. Local接口(LocalPlayer)
你可以在本例的源代碼文件存放目錄j2eetutorial/examples/src/ejb/cmproster中找到以上代碼的源文件,要編譯這些源文件,在命令方式下進(jìn)入j2eetutorial/examples目錄,執(zhí)行antcmproster命令。RosterApp.ear的樣本文件存放在j2eetutorial/examples/ears目錄下。
實(shí)體Bean類
CMP實(shí)現(xiàn)的實(shí)體Bean必須符合CMP的語法規(guī)則。首先Bean類必須定義為公有(public)和抽象(abstract)的。其次要實(shí)現(xiàn)一下內(nèi)容:
1. EntityBean接口
2. 零對(duì)或多對(duì)ejbCreate和ejbPostCreate方法
3. 持久性字段和關(guān)系字段的get和set方法定義為abstract
4. 所有的select方法定義為abstract
5. 商業(yè)方法
CMP的實(shí)體Bean類不能實(shí)現(xiàn)如下方法
1. 查找方法
2. finalize方法
CMP和BMP實(shí)現(xiàn)實(shí)體Bean的代碼比較
因?yàn)镃MP不需要編寫數(shù)據(jù)庫(kù)訪問的代碼,所以CMP實(shí)現(xiàn)的實(shí)體Bean比BMP實(shí)現(xiàn)的實(shí)體Bean的代碼少得多。例如本章中討論的PlayerBean.java源文件要比第5章的代碼文件SavingsAccountBean.java小得多。下表比較了兩種不同類型實(shí)體Bean實(shí)現(xiàn)代碼的不同:
表6-1兩種持久性機(jī)制的編碼比較
不同點(diǎn)
CMP
BMP
企業(yè)Bean類定義
抽象
非抽象
數(shù)據(jù)庫(kù)訪問代碼
由工具產(chǎn)生
開發(fā)者編碼
持久性狀態(tài)
虛擬持久字段表示
代碼中的實(shí)例變量表示
持久性字段和關(guān)系字段的訪問方法
必須
不是必須
findByPrimaryKey方法
由容器處理
開發(fā)者編碼
其他查找方法
容器根據(jù)開發(fā)者定義的EJB QL查詢自動(dòng)處理
開發(fā)者編碼
select方法
容器處理
不需要
ejbCreate方法的返回值
應(yīng)該為null
必須是主鍵類
注意:對(duì)于兩種持久性機(jī)制,商業(yè)方法和Home方法的實(shí)現(xiàn)規(guī)則都是一樣的。參考第5章的商業(yè)方法和Home方法兩節(jié)。
訪問(get和set)方法
CMP實(shí)現(xiàn)的實(shí)體Bean中持久性字段和關(guān)系字段都是虛擬的,你不能把它們?cè)贐ean類中寫成實(shí)例變量,而應(yīng)該在部署描述符里列出它們。要訪問這些字段,你需要在實(shí)體Bean類中定義抽象的get和set方法。
持久性字段的訪問方法
EJB容器根據(jù)部署描述符信息自動(dòng)為持久性字段實(shí)現(xiàn)存儲(chǔ)到數(shù)據(jù)庫(kù)和從數(shù)據(jù)庫(kù)讀取操作。(具體的操作過程可能是在執(zhí)行部署的同時(shí),部署工具就根據(jù)部署描述符的信息生成了對(duì)應(yīng)的數(shù)據(jù)庫(kù)訪問代碼)本例中PlayerEJB的部署描述符中定義了以下持久性字段:
☆ playerId(primary key)
☆ name
☆ position
☆ salary
PlayerBean類中以上字段的訪問方法定義如下:
public abstract String getPlayerId();
public abstract void setPlayerId(String id);
public abstract String getName();
public abstract void setName(String name);
public abstract String getPosition();
public abstract void setPosition(String position);
public abstract double getSalary();
public abstract void setSalary(double salary);
訪問方法名以get或者set開頭,后跟頭字母大寫的對(duì)應(yīng)持久性字段名或者關(guān)系字段名。例如字段salary的訪問方法命名為:getSalary和setSalary。這種命名約定和JavaBean組件的相同。
關(guān)系字段的訪問方法
在RosterApp應(yīng)用程序中,因?yàn)橐粋€(gè)運(yùn)動(dòng)員可以屬于多個(gè)組,一個(gè)PlayerEJB實(shí)例可以關(guān)聯(lián)多個(gè)TeamEJB實(shí)例。為了說明這個(gè)關(guān)系,部署描述符中定義了一個(gè)名叫teams的關(guān)系字段。在PlayerBean類中,teams的訪問方法定義如下:
public abstract Collection getTeams();
public abstract void setTeams(Collection teams);
select方法
select方法和查找方法有很多相同的地方:
☆ select方法可以返回Local或者Remote接口或者它們之一的集合
☆ select方法訪問數(shù)據(jù)庫(kù)
☆ 部署描述符為每個(gè)select方法指定EJB QL查詢
☆ 實(shí)體Bean類并不實(shí)現(xiàn)select方法(只是聲明或者說定義)
當(dāng)然,select方法和查找方法還有一些顯著的區(qū)別:
1. 一個(gè)查找方法可以返回相關(guān)聯(lián)實(shí)體Bean的一個(gè)持久性字段或者字段的集合。而查找方法值可以返回所屬實(shí)體Bean的Local或者Remote接口或者它們之一的集合。
2. 因?yàn)閟elect方法在Local或者Remote接口中沒有被定義,所以它們不能被客戶端訪問,而只能被所屬實(shí)體Bean中實(shí)現(xiàn)的方法調(diào)用(用點(diǎn)像類的私有方法)。select方法通常被商業(yè)方法調(diào)用。
3. select方法在實(shí)體Bean類里定義。BMP的查找方法也在實(shí)體Bean類中定義,但是CMP的查找方法不在實(shí)體Bean類里定義。CMP中的查找方法在Home或者Local Home接口中定義,在部署描述符中定義對(duì)應(yīng)的EJB QL查詢。
PlayerBean類定義了下面這些select方法:
public abstract Collection ejbSelectLeagues(LocalPlayer player)
throws FinderException;
public abstract Collection ejbSelectSports(LocalPlayer player)
throws FinderException;
select的方法簽名規(guī)則:
1. 方法名要以ejbSelect開頭
2. 訪問修飾符必須是public
3. 方法必須聲明為抽象的
4. throws子句必須包括javax.ejb.FinderException
商業(yè)方法
因?yàn)榭蛻舳瞬荒苷{(diào)用select方法,所以PlayerBean類將它們封裝(wraps)在商業(yè)方法getLeagues和getSports中:
public Collection getLeagues() throws FinderException {
LocalPlayer player = (team.LocalPlayer)context.getEJBLocalObject();
return ejbSelectLeagues(player);
}
public Collection getSports() throws FinderException {
LocalPlayer player = (team.LocalPlayer)context.getEJBLocalObject();
return ejbSelectSports(player);
}
實(shí)體Bean方法
因?yàn)樘幚鞢MP實(shí)體Bean的持久性,PlayerBean的生命周期方法都接近于空方法了。ejbCreate方法將參數(shù)賦值給持久性字段以初始化實(shí)體Bean實(shí)例。ejbCreate方法調(diào)用結(jié)束后,容器向數(shù)據(jù)庫(kù)對(duì)應(yīng)表中插入一行。ejbCreate方法實(shí)現(xiàn):
public String ejbCreate (String id, String name,
String position, double salary) throws CreateException {
setPlayerId(id);
setName(name);
setPosition(position);
setSalary(salary);
return null;
}
ejbPostCreate方法必須和對(duì)應(yīng)的ejbCreate方法有相同的參數(shù)簽名和返回值。如果你想在初始化Bean實(shí)例時(shí)設(shè)置關(guān)系字段值,可以實(shí)現(xiàn)ejbPostMethod方法,而不可以在ejbCreate方法中設(shè)置關(guān)系字段值。
除了一個(gè)調(diào)試語句,PlayerBean的ejbRemove方法就是一個(gè)空方法了。容器在刪除數(shù)據(jù)庫(kù)表中對(duì)應(yīng)行之前調(diào)用ejbRemove方法。
容器自動(dòng)同步實(shí)體Bean狀態(tài)和數(shù)據(jù)庫(kù)數(shù)據(jù)。容器從數(shù)據(jù)庫(kù)中讀取實(shí)體狀態(tài)后調(diào)用ejbLoad方法,同樣的方式,在將實(shí)體狀態(tài)存入數(shù)據(jù)庫(kù)前調(diào)用ejbStore方法。(這句話有些費(fèi)解,因?yàn)樵贐MP中數(shù)據(jù)庫(kù)的同步是在ejbLoad和ejbStore這兩個(gè)方法里實(shí)現(xiàn)的,難道部署工具或者容器為CMP生成的實(shí)現(xiàn)子類不使用這兩個(gè)方法來實(shí)現(xiàn)數(shù)據(jù)庫(kù)同步的?)
Local Home接口
Local Home接口定義本地客戶端調(diào)用的create方法、查找方法和Home方法。
create方法的語法規(guī)則如下:
1. 方法名以create開頭
2. 和對(duì)應(yīng)的實(shí)體Bean類里定義的ejbCreate方法有相同的參數(shù)簽名
3. 返回實(shí)體Bean的Local接口
4. throws子句包括對(duì)應(yīng)ejbCreate方法throws子句中出現(xiàn)的所有異常加上javax.ejb.CreateException異常
查找方法的規(guī)則:
1. 方法名以find開頭
2. 返回實(shí)體Bean的Local接口或它的集合
3. throws子句包括javax.ejb.FinderException異常
4. 必須定義findByPrimaryKey方法
下面是LocalPlayerHome的部分代碼:
package team;
import java.util.*;
import javax.ejb.*;
public interface LocalPlayerHome extends EJBLocalHome {
public LocalPlayer create (String id, String name,
String position, double salary)
throws CreateException;
public LocalPlayer findByPrimaryKey (String id)
throws FinderException;
public Collection findByPosition(String position)
throws FinderException;
...
public Collection findByLeague(LocalLeague league)
throws FinderException;
...
}
Local接口
該接口定義了本地客戶端調(diào)用的商業(yè)方法和字段訪問方法。PlayerBean類實(shí)現(xiàn)了兩個(gè)商業(yè)方法getLeagues和getSports,同時(shí)還為持久性字段和關(guān)系字段定義了很多get和set訪問方法。但是客戶端不能調(diào)用set方法,因?yàn)長(zhǎng)ocalPlayer接口中沒有定義這些set方法。但是get方法客戶端可以訪問。下面是LocalPlayer的實(shí)現(xiàn)代碼:
package team;
import java.util.*;
import javax.ejb.*;
public interface LocalPlayer extends EJBLocalObject {
public String getPlayerId();
public String getName();
public String getPosition();
public double getSalary();
public Collection getTeams();
public Collection getLeagues() throws FinderException;
public Collection getSports() throws FinderException;
}
三、RosterApp配置說明
本節(jié)將引導(dǎo)你為CMP實(shí)現(xiàn)的實(shí)體Bean配置部署描述符。在這個(gè)過程中,還將討論deplouytool工具中出現(xiàn)的重要的選項(xiàng)頁和對(duì)話框。
請(qǐng)先運(yùn)行deploytool并打開j2eetutorial/examples/ears目錄下的RosterApp.ear文件。
RosterApp應(yīng)用程序配置
在屬性視圖中選中RosterApp節(jié)點(diǎn)以查看應(yīng)用程序的部署信息。
General頁(RosterApp)
Contents域顯示了RosterApp.ear中包含的文件,包括兩個(gè)EJB JAR文件(team-ejb.jar和roster-ejb.jar)和J2EE應(yīng)用程序客戶端JAR文件(roster-ac.jar)。如圖6-2:
圖 6-2 RosterApp 的General 頁
JNDI Names頁(RosterApp)
Application表列出了RosterApp應(yīng)用程序中的企業(yè)Bean的JNDI名。
References表有兩個(gè)條目,EJB Ref條目為RosterClient客戶端映射RosterEJB會(huì)話Bean的引用名(ejb/SimpleRoster)。Resource條目指定TeamJAR模塊中的實(shí)體Bean訪問的數(shù)據(jù)庫(kù)的JNDI名。
RosterClient客戶端配置
展開RosterApp節(jié)點(diǎn),選中RosterClient節(jié)點(diǎn),將顯示客戶端配置信息。
JAR File頁(RosterClient)
Contents域顯示了roster-ac.jar包含的文件:兩個(gè)XML文件(部署描述符文件)和一個(gè)類文件(RosterClient.class)。
EJB Refs頁(RosterCliet)
RosterClient客戶端訪問一個(gè)企業(yè)Bean:RosterEJB會(huì)話Bean。因?yàn)槭沁h(yuǎn)程訪問,Interfaces列選擇Remote,Local/Remote列填寫會(huì)話Bean的Remote接口(roster.Roster)。
RosterJAR的設(shè)置
在樹視圖中選中RosterJAR節(jié)點(diǎn)。該JAR文件包含RosterEJB會(huì)話Bean。
General頁(RosterJAR)
Contents域列出了三個(gè)包:roster包包含RosterEJB需要的類文件——會(huì)話Bean類,Remote接口和Home接口;team包包含RosterEJB要訪問的實(shí)體Bean的Local接口;util包里是應(yīng)用程序用到的一些實(shí)用類(utility classes)。
RosterEJB
展開RosterJAR節(jié)點(diǎn)點(diǎn)選RosterEJB節(jié)點(diǎn)。
General頁(RosterEJB)
本例中General選項(xiàng)頁顯示RosterEJB是一個(gè)遠(yuǎn)程訪問的有狀態(tài)會(huì)話Bean。因?yàn)樗恢С直镜卦L問,所以Local Interface域?yàn)榭铡?div style="height:15px;">
EJB Refs頁(RosterEJB)
RosterEJB會(huì)話Bean訪問三個(gè)實(shí)體Bean:PlayerEJB、TeamEJB和LeagueEJB。因?yàn)檫@些訪問都是本地訪問,這些引用條目中的Interfaces列中都定為L(zhǎng)ocal,Home Interface列顯示的是這些實(shí)體Bean的Local Home接口。Local/Remote Interfaces列顯示的是這些實(shí)體Bean的Local接口。
選中表中的一行,可以查看運(yùn)行時(shí)部署信息。例如當(dāng)你選擇Coded Name列為ejb/SimpleLeague的一行時(shí),LeagueEJB就顯示在Enterprise Bean Name域里。Enterpri Bean Name域需要設(shè)置成被引用的企業(yè)Bean的名字(在左邊樹視圖中顯示的名字)。
TeamJAR配置
點(diǎn)選樹視圖中的TeamJAR節(jié)點(diǎn)。該JAR文件包含三個(gè)相互關(guān)聯(lián)的實(shí)體Bean:LeagueEJB、TeamEJB和PlayerEJB。
General頁(TeamJAR)
Contents域顯示了該JAR文件中的兩個(gè)包:team和util。team包包含三個(gè)實(shí)體Bean的類文件、Local接口文件和Local Home接口文件。Util包就不再介紹了。
Relationships頁(TeamJAR)
如圖6-3,CMP實(shí)體Bean之間的關(guān)系在這個(gè)選項(xiàng)頁中定義。
圖 6-3 TeamJAR的Relationships頁
Container Managed Relationships表中定義了兩個(gè)關(guān)系:TeamEJB-PlayerEJB和LeagueEJB-TeamEJB。在TeamEJB-PlayerEJB關(guān)系中,TeamEJB被當(dāng)作EJB A而PlayerEJB被當(dāng)作EJB B(當(dāng)然你也可以交換它們的位置,這并不影響關(guān)系本身)。
關(guān)系編輯對(duì)話框(TeamJAR)
在上圖所示的Relationship頁中選擇表中的一行點(diǎn)擊Edit按鈕,就會(huì)彈出關(guān)系編輯對(duì)話框。(當(dāng)然Add按鈕也可以,只不過不需要選擇已有關(guān)系,因?yàn)?#8230;…)。如圖6-4是TeamEJB-PlayerEJB關(guān)系的編輯對(duì)話框,下面詳細(xì)介紹它們的關(guān)系。
TeamEJB-PlayerEJB關(guān)系
Multiplicity組合框提供四種可選的關(guān)系類型(因?yàn)檫@里是單向從A到B,所以一對(duì)多和多對(duì)一是兩種類型,其實(shí)可以在下面的EJB組合框中調(diào)換關(guān)系雙方的位置而讓它們合成一種)。TeamEJB-PlayerEJB是多對(duì)多關(guān)系(many to many(*:*)選項(xiàng))。
Enterprise Bean A框里描述了TeamEJB在關(guān)系中的信息。Field Referencing Bean B組合框里選擇了TeamEJB中的關(guān)系字段(players),這個(gè)字段對(duì)應(yīng)TeamBean.java文件中定義的以下兩個(gè)訪問方法:
public abstract Collection getPlayers();
public abstract void setPlayers(Collection players);
圖 6-4TeamJAR的關(guān)系編輯對(duì)話框
FieldType組合框選擇的是java.util.Collection以匹配為訪問方法中player字段的類型。因?yàn)樵趯?duì)TeamEJB在關(guān)系中PlayerEJB是“多”的一方(在多對(duì)多關(guān)系中雙方都是“多”),所以player字段的類型是多值對(duì)象(集合)。
TeamEJB-PlayerEJB的關(guān)系是雙向的——關(guān)系的雙方都有一個(gè)關(guān)系字段標(biāo)志關(guān)聯(lián)的實(shí)體Bean的實(shí)例。如果關(guān)系不是雙向的,沒有關(guān)系字段的一方在Field Referenceing組合框中選擇<none>。
LeagueEJB-TeamEJB關(guān)系
在關(guān)系編輯對(duì)話框里,LeagueEJB-TeamEJB關(guān)系的Multiplicity組合框選擇的是One to Many(因?yàn)橐粋€(gè)社團(tuán)可以有多個(gè)組,而且這里選定后,Enterprise Bean A就只能是LeagueEJB了)。
LeagueEJB中用關(guān)系字段teams來表示該社團(tuán)里所有的組。因?yàn)門eamEJB是關(guān)系中“多”的一方,所以teams字段是一個(gè)集合。而LeagueEJB是“一”的一方,所以TeamEJB中l(wèi)eague是單個(gè)的LocalLeaguer類型對(duì)象。TeamBean.java通過如下訪問方法定義關(guān)系字段league:
public abstract LocalLeague getLeague();
public abstract void setLeague(LocalLeague players);
在LeagueEJB-TeamEJB關(guān)系中定義了關(guān)聯(lián)刪除,TeamEJB中Delete When A Is Deleted符選框被選中。這樣當(dāng)一個(gè)LeagueEJB實(shí)例被刪除時(shí),與它相關(guān)聯(lián)的TeamEJB實(shí)例也將自動(dòng)地被刪除,這就是關(guān)聯(lián)刪除。LeagueEJB中相同的符選框并沒有選中,不能刪除一個(gè)組就刪除整個(gè)社團(tuán),因?yàn)檫€有其他組在社團(tuán)中。一般在關(guān)系中“多”的一方才會(huì)被關(guān)聯(lián)刪除,另一方不會(huì)被自動(dòng)刪除。
PlayerEJB
在樹視圖中選擇PlayerEJB節(jié)點(diǎn)(TeamJAR的字節(jié)點(diǎn)之一)。
General頁(PlayerEJB)
這一頁顯示企業(yè)Bean類和EJB接口。因?yàn)镻layerEJB是容器管理關(guān)系的靶子,所以它有本地接口(Local和Local Home接口),同時(shí)它不需要允許遠(yuǎn)程訪問,所以沒有遠(yuǎn)程接口(Remote和Home接口)。
Entity頁(PlayerEJB)
如圖6-5,在這一頁上面的單選按鈕組定義企業(yè)實(shí)體Bean的持久性類型。為PlayerEJB選定的是container-managed persistence(2.0),就是CMP2.0。因?yàn)镃MP1.0不提供容器管理的關(guān)系服務(wù),所以不推薦使用。(這些版本號(hào)是EJB規(guī)范的版本號(hào),而不是J2EE SDK的版本號(hào))
Fields To Be Persisted列表框列出了PlayerBean.java中定義了訪問方法的所有持久性字段和關(guān)系字段。持久性字段前面的選擇框必須被選中,而關(guān)系字段不能不選中。就是說關(guān)系字段(外鍵)不在本實(shí)體Bean中被持久化(這里或許是因?yàn)閿?shù)據(jù)庫(kù)表本身是用參照約束實(shí)現(xiàn)的外鍵關(guān)聯(lián),所以關(guān)系字段不需要在這里持久化,如果數(shù)據(jù)表關(guān)系是用應(yīng)用程序編碼檢查來實(shí)現(xiàn),那么這里就應(yīng)該讓關(guān)系字段也被持久化,但是這時(shí)這個(gè)字段還是不是關(guān)系字段呢?)。PlayerEJB實(shí)體Bean的關(guān)系字段只有一個(gè):teams。
abstract schema name是Player,這個(gè)名字代表PlayerEJB實(shí)體Bean的所有持久性字段和關(guān)系字段(抽象模式名標(biāo)志一個(gè)定義持久性字段和關(guān)系字段的抽象模式)。這個(gè)抽象模式名將在為PlayerEJB定義的EJB QL 查詢中被引用。EJB QL將在第8章論述。
圖 6-5PlayerEJB的Entity頁
Finder/Select Methods對(duì)話框(PlayerEJB)
在Entity頁點(diǎn)擊Finder/Select Methods按鈕會(huì)打開Finder/Select Methods對(duì)話框,如圖6-6。你可以在這個(gè)對(duì)話框里查看和編輯為CMP實(shí)體Bean的查找和Select方法寫的EJB QL查詢。
圖 6-6 Finder/Select Methods 對(duì)話框
Entity Deployment Settings對(duì)話框(PlayerEJB)
在Entity頁點(diǎn)擊Deployment Settings按鈕打開該對(duì)話框,該對(duì)話框用來設(shè)置CMP實(shí)體Bean的運(yùn)行時(shí)配置信息。這些信息是J2EE SDK特有的,其他的J2EE平臺(tái)可能有些不同。在J2EE SDK中,實(shí)體Bean的持久性字段存儲(chǔ)在關(guān)系數(shù)據(jù)庫(kù)中,在Database Table框中你可以確定是否讓服務(wù)器自動(dòng)創(chuàng)建和刪除數(shù)據(jù)庫(kù)中的表。如果你想把數(shù)據(jù)保存在數(shù)據(jù)庫(kù)中,就不選中Delete table on undeploy復(fù)選框,否則當(dāng)你從服務(wù)器卸載實(shí)體Bean時(shí),表將被刪除。
J2EE服務(wù)器通過SQL語句訪問數(shù)據(jù)庫(kù),用CMP實(shí)現(xiàn)實(shí)體Bean時(shí)你不需要自己編寫這些SQL語句,點(diǎn)擊General Default SQL按鈕deploytool工具會(huì)自動(dòng)生成這些語句。然后在Method表格里選中任意一個(gè)方法,會(huì)在右邊的SQL Query域里看到為這個(gè)方法生成的SQL語句,你可以在這里修改這些生成的語句。
對(duì)查找和Select方法,對(duì)應(yīng)的EJB QL查詢也會(huì)顯示在下面的EJB QL Query域里。在你點(diǎn)擊General Default SQL按鈕時(shí),deploytool把EJB QL查詢轉(zhuǎn)換成SQL語句,如果你修改了EJB QL查詢,你應(yīng)該讓deploytool重新生成SQL語句。
點(diǎn)擊Container Methods單選按鈕,可以看到為容器管理方法生成的SQL語句。如createTable方法的創(chuàng)建表SQL語句,當(dāng)然還有刪除表的SQL語句。
當(dāng)容器創(chuàng)建一個(gè)PlayerEJB實(shí)例時(shí),它生成一條插入數(shù)據(jù)(INSERT)的SQL語句,要查看這條語句,在Method表各種選擇createRow方法,這條語句的VALUES子句中的變量是Home接口中create方法的對(duì)應(yīng)參數(shù)。
Database Deployment Settings對(duì)話框(PlayerEJB)
在Entity Deployment Settings對(duì)話框中點(diǎn)擊Database Settings按鈕打開該對(duì)話框。在這里你可以為數(shù)據(jù)庫(kù)指定JNDI名,這是非常重要的,因?yàn)闆]有JNDI名你將無法訪問數(shù)據(jù)庫(kù)。本例中的數(shù)據(jù)庫(kù)JNDI名為jdbc/Cloudscape,用戶名和密碼為空。
四、RosterApp中的方法調(diào)用
為了說明組件之間如何相互協(xié)作,本節(jié)描述實(shí)現(xiàn)特定功能時(shí)的方法調(diào)用順序。這些組件的源文件在j2eetutorial/examples/src/ejb/cmproster目錄下。
“新建”一個(gè)運(yùn)動(dòng)員
1.RosterClient客戶端程序
RosterClient客戶端程序調(diào)用RosterEJB會(huì)話Bean的createPlayer商業(yè)方法。在下面的代碼中myRoster對(duì)象是Roster類型(RosterEJB的遠(yuǎn)程接口),參數(shù)是PlayerDetails對(duì)象,該對(duì)象封裝了一個(gè)運(yùn)動(dòng)員的所有信息。(PlayerDetails是一個(gè)值對(duì)象,用來在遠(yuǎn)程調(diào)用間傳遞實(shí)體信息,關(guān)于值對(duì)象模式的更多信息,參考《J2EE核心模式》一書)。
myRoster.createPlayer(new PlayerDetails("P1", "Phil Jones", "goalkeeper", 100.00));
2.RosetEJB
會(huì)話Bean的createPlayer方法創(chuàng)建一個(gè)PlayerEJB實(shí)體Bean實(shí)例。因?yàn)镻layerEJB只有本地接口,所以create方法在Local Home接口LocalPlayerHome中定義。下面的代碼中playerHome是LocalPlayerHome類型的對(duì)象:
public void createPlayer(PlayerDetails details) {
try {
LocalPlayer player = playerHome.create(details.getId(),
details.getName(), details.getPosition(),
details.getSalary());
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
}
3.PlayerEJB
ejbCreate方法用set訪問方法將參數(shù)值賦給持久性字段,該方法調(diào)用后容器生成一個(gè)INSERT SQL語句將持久性字段寫入數(shù)據(jù)庫(kù):
public String ejbCreate (String id, String name,
String position, double salary) throws CreateException {
setPlayerId(id);
setName(name);
setPosition(position);
setSalary(salary);
return null;
}
將運(yùn)動(dòng)員加入組
1.RosterClient客戶端
客戶端調(diào)用RosterEJB的addPlayer方法(參數(shù)P1和T1分別代表Player和TeamEJB實(shí)例的主鍵):
myRoster.addPlayer("P1", "T1");
2.RosterEJB
addPlayer方法分兩個(gè)步驟完成工作:首先它調(diào)用findByPrimaryKey查找PlayerEJB和TeamEJB實(shí)例;然后直接調(diào)用TeamEJB的addPlayer方法。代碼如下:
public void addPlayer(String playerId, String teamId) {
try {
LocalTeam team = teamHome.findByPrimaryKey(teamId);
LocalPlayer player =
playerHome.findByPrimaryKey(playerId);
team.addPlayer(player);
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
}
3.TeamEJB
TeamEJB有一個(gè)關(guān)系字段players,它是屬于這個(gè)隊(duì)伍的所有運(yùn)動(dòng)員的集合(Collection),它的訪問方法如下:
public abstract Collection getPlayers();
public abstract void setPlayers(Collection players);
addPlayer方法縣調(diào)用getPlayers方法得到關(guān)聯(lián)的LocalPlayer對(duì)象的集合,然后調(diào)用集合的add方法新加入一個(gè)運(yùn)動(dòng)員:
public void addPlayer(LocalPlayer player) {
try {
Collection players = getPlayers();
players.add(player);
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
}
“刪除”一個(gè)運(yùn)動(dòng)員
1.RosterClient
刪除運(yùn)動(dòng)員P4,客戶端調(diào)用RosterEJH的removePlayer方法:
myRoster.removePlayer("P4");
2.RosterEJB
removePlayer方法調(diào)用findByPrimaryKey方法定位倒要?jiǎng)h除的PlayerEJB實(shí)例然后調(diào)用實(shí)例的remove方法。這個(gè)調(diào)用會(huì)通知容器在數(shù)據(jù)庫(kù)中刪除對(duì)應(yīng)的紀(jì)錄,容器還同時(shí)刪除相關(guān)聯(lián)的TeamEJB的player關(guān)系字段中該實(shí)例的引用以更新TeamEJB-PlayerEJB之間的關(guān)系。下面是RosterEJB的removePlayer方法:
public void removePlayer(String playerId) {
try {
LocalPlayer player =
playerHome.findByPrimaryKey(playerId);
player.remove();
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
}
從組中開除運(yùn)動(dòng)員
1.RosterClient
將運(yùn)動(dòng)員P2從組T1中刪除的客戶端調(diào)用:
myRoster.dropPlayer("P2", "T1");
2.RosterEJB
dropPlayer方法的調(diào)用和addPlayer很像,她先找到PlayerEJB和TeamEJB的實(shí)例,然后調(diào)用TeamEJB的dropPlayer方法:
public void dropPlayer(String playerId, String teamId) {
try {
LocalPlayer player =
playerHome.findByPrimaryKey(playerId);
LocalTeam team = teamHome.findByPrimaryKey(teamId);
team.dropPlayer(player);
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
}
3.TeamEJB
dropPlayer方法會(huì)更新TeamEJB-PlayerEJB關(guān)系。首先它得到關(guān)系字段players 對(duì)應(yīng)的LocalPlayer對(duì)象集合,然后調(diào)用集合的remove方法刪除目標(biāo)運(yùn)動(dòng)員。代碼如下:
public void dropPlayer(LocalPlayer player) {
try {
Collection players = getPlayers();
players.remove(player);
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
}
獲得一個(gè)組里的所有運(yùn)動(dòng)員
1.RosterClient
客戶段調(diào)用RosterEJB的getPlayersOfTeam方法來獲得某個(gè)組的成員,該方法返回包含PlayerDetails對(duì)象的ArrayList。PlayerDetails是PlayerEJB的值對(duì)象(《J2EE核心模式》),包含的數(shù)據(jù)成員playerId、name、salary都是PlayerEJB的持久性字段??蛻舳苏{(diào)用代碼如下:
playerList = myRoster.getPlayersOfTeam("T2");
2.RosterEJB
RosterEJB的getPlayersOfTeam方法先調(diào)用TeamEJB的findByPrimaryKey方法找到對(duì)應(yīng)的實(shí)例,然后調(diào)用TeamEJB的getPlayers方法,最后調(diào)用copyPlayerToDetails方法將每一個(gè)運(yùn)動(dòng)員的數(shù)據(jù)拷貝到PlayDetails中組成返回集合。代碼如下:
public ArrayList getPlayersOfTeam(String teamId) {
Collection players = null;
try {
LocalTeam team = teamHome.findByPrimaryKey(teamId);
players = team.getPlayers();
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
return copyPlayersToDetails(players);
}
copyPlayerToDetails方法的實(shí)現(xiàn)如下:
private ArrayList copyPlayersToDetails(Collection players) {
ArrayList detailsList = new ArrayList();
Iterator i = players.iterator();
while (i.hasNext()) {
LocalPlayer player = (LocalPlayer) i.next();
PlayerDetails details =
new PlayerDetails(player.getPlayerId(),
player.getName(), player.getPosition(),
player.getSalary());
detailsList.add(details);
}
return detailsList;
}
3.TeamEJB
TeamEJB的getPlayers方法是關(guān)系字段players的訪問方法:
public abstract Collection getPlayers();
對(duì)本地客戶可用,因?yàn)樗窃贚ocal接口中被定義:
public Collection getPlayers();
該方法向本地客戶返回關(guān)系字段的引用,如果客戶接著修改了得到的結(jié)果,實(shí)體Bean中的關(guān)系字段也跟著被修改(因?yàn)槭且?,所以操作的是同一個(gè)對(duì)象)。例如本地客戶可以用如下方法開除一個(gè)運(yùn)動(dòng)員:
LocalTeam team = teamHome.findByPrimaryKey(teamId);
Collection players = team.getPlayers();
players.remove(player);
下面講到的方法描述如何避免這種危險(xiǎn)。
獲取組成員的副本
這一小節(jié)討論下面兩項(xiàng)技術(shù):
☆ 過濾返回給遠(yuǎn)程客戶端的信息
☆ 防止本地客戶直接修改關(guān)系字段
1.RosterClient
如果你想在返回給客戶端的結(jié)果中過濾掉運(yùn)動(dòng)員的薪水信息,你應(yīng)該調(diào)用RosterEJB的getPlayersOfTeamCopy方法,該方法跟getPlayersOfTeam的唯一區(qū)別就是它把每個(gè)運(yùn)動(dòng)員的薪水都設(shè)置為0。客戶端調(diào)用代碼:
playerList = myRoster.getPlayersOfTeamCopy("T5");
2.RosterEJB
getPlayersOfTeamCopy方法并不像getPlayersOfTeam方法一樣調(diào)用getPlayers訪問方法,它調(diào)用LocalTeam接口中定義的getCopyOfPlayers商業(yè)方法。從getPlayersOfTeamCopy方法得到的返回值不能修改TeamEJB的關(guān)系字段players。代碼如下:
public ArrayList getPlayersOfTeamCopy(String teamId) {
ArrayList playersList = null;
try {
LocalTeam team = teamHome.findByPrimaryKey(teamId);
playersList = team.getCopyOfPlayers();
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
return playersList;
}
3.TeamEJB
TeamEJB的getCopyOfPlayers方法返回包含PlayeDetails對(duì)象的ArrayList。為了創(chuàng)建這個(gè)ArrayList,它必須遍歷關(guān)系字段players集合并將每一個(gè)元素的信息拷貝到一個(gè)PlayerDetails對(duì)象中,因?yàn)橐^濾薪水字段,所以只拷貝了salary除外的字段,而salary被直接置為0。當(dāng)客戶端調(diào)用getPlayerOfTeamCopy方法時(shí),隱藏了運(yùn)動(dòng)員的薪水信息。代碼如下:
public ArrayList getCopyOfPlayers() {
ArrayList playerList = new ArrayList();
Collection players = getPlayers();
Iterator i = players.iterator();
while (i.hasNext()) {
LocalPlayer player = (LocalPlayer) i.next();
PlayerDetails details =
new PlayerDetails(player.getPlayerId(),
player.getName(), player.getPosition(), 0.00);
playerList.add(details);
}
return playerList;
}
根據(jù)位置查詢運(yùn)動(dòng)員
1.RosterClient
客戶端調(diào)用RosterEJB的getPlayersByPosition方法:
playerList = myRoster.getPlayersByPosition("defender");
2.RosterEJB
RosterEJB的getPlayersByPosition方法調(diào)用PlayerEJB的findByPosition方法得到特定位置得運(yùn)動(dòng)員集合:
public ArrayList getPlayersByPosition(String position) {
Collection players = null;
try {
players = playerHome.findByPosition(position);
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
return copyPlayersToDetails(players);
}
3.PlayerEJB
LocalPlayerHome接口定義了findByPosition方法:
public Collection findByPosition(String position)
throws FinderException;
因?yàn)镻layerEJB是CMP實(shí)現(xiàn)的實(shí)體Bean,所以實(shí)體Bean類PlayerBean并不實(shí)現(xiàn)查找方法,而是在部署描述符中為每一個(gè)查找方法指定EJB QL查詢。下面是findByPosition方法的EJB QL查詢:
SELECT DISTINCT OBJECT(p) FROM Player p
WHERE p.position = ?1
Deploytool工具會(huì)將上面的EJB QL查詢轉(zhuǎn)換成對(duì)應(yīng)的SELECT語句。在容器調(diào)用findByPositiong方法的時(shí)候,SELECT語句也將被執(zhí)行。
查詢運(yùn)動(dòng)員的運(yùn)動(dòng)項(xiàng)目
1.RosterClient
客戶段調(diào)用RosterEJB的getSportsOfPlayer方法:
sportList = myRoster.getSportsOfPlayer("P28");
2.RosterEJB
RosterEJB的getSportsOfPlayer方法返回一個(gè)運(yùn)動(dòng)員可以參與的運(yùn)動(dòng)項(xiàng)目的String類型的ArrayList,它直接調(diào)用PlayerEJB的getSports方法得到這個(gè)ArrayList。代碼如下:
public ArrayList getSportsOfPlayer(String playerId) {
ArrayList sportsList = new ArrayList();
Collection sports = null;
try {
LocalPlayer player =
playerHome.findByPrimaryKey(playerId);
sports = player.getSports();
} catch (Exception ex) {
throw new EJBException(ex.getMessage());
}
I(yíng)terator i = sports.iterator();
while (i.hasNext()) {
String sport = (String) i.next();
sportsList.add(sport);
}
return sportsList;
}
3.PlayerEJB
PlayerEJB的getSports方法只是簡(jiǎn)單的調(diào)用ejbSelectSports方法。因?yàn)閑jbSelectSports方法的參數(shù)是LocalPlayer類型,所以要傳遞一個(gè)實(shí)體Bean實(shí)例的引用給方法。代碼如下:
public Collection getSports() throws FinderException {
LocalPlayer player =
(team.LocalPlayer)context.getEJBLocalObject();
return ejbSelectSports(player);
}
ejbSelectSports方法的代碼:
public abstract Collection ejbSelectSports(LocalPlayer player)
throws FinderException;
ejbSelectSports的EJB QL查詢語句:
SELECT DISTINCT t.league.sport
FROM Player p, IN (p.teams) AS t
WHERE p = ?1
在部署PlayerEJB前,你要用deploytool來產(chǎn)生對(duì)應(yīng)的SELECT語句。當(dāng)容器調(diào)用ejbSelectSports方法時(shí),也同時(shí)執(zhí)行SELECT語句。
五、運(yùn)行RosterApp應(yīng)用程序
啟動(dòng)用到的軟件
1. 在命令模式下執(zhí)行cloudscape -start命令啟動(dòng)Cloudscape數(shù)據(jù)庫(kù)服務(wù)器。
2. 執(zhí)行j2ee -verbose命令啟動(dòng)J2EE服務(wù)器。
3. 執(zhí)行deploytool命令運(yùn)行deploytool部署工具。
部署該應(yīng)用程序
1. 在deploytool中打開RosterApp.ear(j2eetutorial/examples/ears directory)文件
2. 部署
a) 選定樹視圖中的RosterApp節(jié)點(diǎn)
b) 執(zhí)行Tools\Deploy菜單命令
c) 在Introduction對(duì)話框中,選中Return Client JAR復(fù)選框
d) 在Client JAR File域中輸入文件名(或者用Browse按鈕設(shè)置):j2eetutorial/examples/ears/RosterAppClient.jar
e) 一路Next直到Finish
運(yùn)行客戶端
1. 在命令模式下進(jìn)入j2eetutorial/examples/ears目錄
2. 設(shè)置環(huán)境變量APPCPATH為RosterAppClient.jar所在目錄
3. 執(zhí)行如下命令:
runclient -client RosterApp.ear -name RosterClient -textauth
4. 用戶名:guest。密碼:guest123。
六、用deploytool工具部署CMP實(shí)現(xiàn)的實(shí)體Bean
在第2章講述了打包和部署企業(yè)Bean的基本步驟,這一節(jié)將介紹deploytool部署CMP實(shí)現(xiàn)的實(shí)體Bean時(shí)的不同之處,圖例參考RosterApp配置說明一節(jié)。
指定企業(yè)Bean類型
在新建企業(yè)Bean向?qū)В∟ew\Enterprise Bean菜單)中指定企業(yè)Bean類型和持久性管理機(jī)制。
1.在EJB JAR對(duì)話框中點(diǎn)擊Edit按鈕打開Edite Contents對(duì)話框,添加實(shí)體Bean和關(guān)聯(lián)的實(shí)體Bean需要的類
2.在General對(duì)話框中,選擇Bean類型為:Entity
3.在同一個(gè)對(duì)話框中指定Bean類和用到的接口類(遠(yuǎn)程或者本地或者兩者都有)
4.在Entity Settings對(duì)話框中選擇持久性機(jī)制Container managed persistence(2.0)
選擇持久性字段和抽象模式名
可以在上面提到的Entity Settings對(duì)話框中設(shè)置。這里我們?cè)贓ntity選項(xiàng)頁中設(shè)置(在樹視圖中選中上面新建的實(shí)體Bean節(jié)點(diǎn))。見圖6-5
1.在Fields To Be Persisted類表中,選中需要存儲(chǔ)到數(shù)據(jù)庫(kù)中的字段。這些字段名是根據(jù)命名規(guī)范從定義的訪問方法中讀出的。
2.指定主鍵類合主鍵字段,主鍵字段唯一標(biāo)志一個(gè)實(shí)體Bean實(shí)例
3.在Abstract Schema Name域中輸入一個(gè)抽象模式名,該名字在EJB QL查詢中被引用
為查找方法和Select方法定義EJB QL查詢
在Finder/Select Mothods對(duì)話框中定義EJB QL查詢,見圖6-6。
1.在Entity頁中點(diǎn)擊Finder/Select Methods按鈕
2.在Method表各種選擇要定義EJB QL查詢的方法,在EJB-QL域中輸入語句
產(chǎn)生SQL、指定表創(chuàng)建機(jī)制(Deploy Settings對(duì)話框),指定數(shù)據(jù)庫(kù)JNDI名、訪問用戶名和密碼(Database Settings對(duì)話框),定義關(guān)系(EJB JAR節(jié)點(diǎn)的Relationship頁,圖6-3,Edit Relationships對(duì)話框,圖6-4)都請(qǐng)參考RosterApp配置說明一節(jié)的對(duì)應(yīng)內(nèi)容。
七、CMP的主鍵
主鍵類并不一定是J2SE或者J2EE的標(biāo)準(zhǔn)類庫(kù)中的類(特別是你的主鍵是組合字段的時(shí)候),這是你就要自己新建主鍵類并把它和實(shí)體Bean打包在一起。
主鍵類
下面的例子中,PurchaseOrderKey類為PurchaseOrderEJB實(shí)現(xiàn)一個(gè)組合主鍵,該主鍵由有兩個(gè)數(shù)據(jù)成員productModel和vendorId對(duì)應(yīng)實(shí)體Bean的兩個(gè)持久性字段:
public class PurchaseOrderKey implements java.io.Serializable {
public String productModel;
public String vendorId;
public PurchaseOrderKey() { };
public String getProductModel() {
return productModel;
}
public String getVendorId() {
return vendorId;
}
public boolean equals(Object other) {
if (other instanceof PurchaseOrderKey) {
return (productModel.equals(
((PurchaseOrderKey)other).productModel) &&
vendorId.equals(
((PurchaseOrderKey)other).vendorId));
}
return false;
}
public int hashCode() {
return productModel.concat(vendorId).hashCode();
}
}
對(duì)于CMP實(shí)體Bean的主鍵類有以下要求:
☆ 該類必須是public公有類
☆ 數(shù)據(jù)成員是實(shí)體Bean的持久性字段的子集
☆ 有一個(gè)public的缺省構(gòu)造函數(shù)(沒有實(shí)現(xiàn)任何構(gòu)造函數(shù)或者自己實(shí)現(xiàn)一個(gè)無參構(gòu)造函數(shù)和其他構(gòu)造函數(shù))
☆ 重載hashCode和equals(Object other)方法(繼承自O(shè)bject類)
☆ 可序列化(實(shí)現(xiàn)Serializble接口)
實(shí)體Bean類中的主鍵
在PurchaseBean類中,主鍵類對(duì)應(yīng)字段(vendorId和productModel)的訪問方法定義如下:
public abstract String getVendorId();
public abstract void setVendorId(String id);
public abstract String getProductModel();
public abstract void setProductModel(String name);
下面是PurchaseOrderBean類ejbCreate方法的代碼,它的返回類型是主鍵類但是返回語句缺返回null。雖然不是必需的,null是CMP機(jī)制推薦的返回值。這樣可以節(jié)省資源,因?yàn)閷?shí)體Bean并不需要產(chǎn)生主鍵類的實(shí)例并返回。(This approach saves overhead because the bean does not have to instantiate the primary key class for the return value.這句話有些疑義,它的意思應(yīng)該是說CMP機(jī)制會(huì)自動(dòng)處理這些動(dòng)作,所以我們不必自己多事浪費(fèi)時(shí)間)。
public PurchaseOrderKey ejbCreate (String vendorId, String productModel, String productName)
throws CreateException {
setVendorId(vendorId);
setProductModel(productModel);
setProductName(productName);
return null;
}
產(chǎn)生主鍵值
一些實(shí)體Bean的主鍵值對(duì)于商業(yè)實(shí)體有特殊意義。例如:一個(gè)表示向呼叫中心打入的電話呼叫的實(shí)體Bean,主鍵應(yīng)該包括呼叫被接收時(shí)的時(shí)間戳。也有很多實(shí)體Bean的主鍵值是任意的,只要它們是唯一的。對(duì)CMP實(shí)現(xiàn)的實(shí)體Bean,容器可以自動(dòng)為實(shí)體Bean生成主鍵值,不過它對(duì)實(shí)體Bean有一些額外的要求:
☆ 在部署描述符中,定義主鍵類被為java.lang.Object,不指定主鍵字段
☆ 在Home接口中,findByPrimaryKey方法的參數(shù)是java.lang.Object
☆ 實(shí)體Bean類中,ejbCreate的返回值類型是java.lang.Object
這些實(shí)體Bean的主鍵值保存在只有容器可以訪問的內(nèi)部字段中,你不能讓它和持久性字段或者任何其他數(shù)據(jù)成員產(chǎn)生聯(lián)系,然而你還是可以通過調(diào)用getPrimaryKey方法得到主鍵值,然后你可以調(diào)用findByPrimaryKey來定位實(shí)體Bean實(shí)例了。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Java面試題集
第二十九天-加強(qiáng)1-Junit&類加載&反射&Properties&BeanUtils&xml&動(dòng)態(tài)代理
EJB3.0規(guī)范解讀
SpringBoot 注解最全詳解 (整合超詳細(xì)版本)
Java中的數(shù)據(jù)驗(yàn)證
java面試
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服