關于實體 Bean
![]()
實體 Bean
實體?Bean?特征
實體?Bean?在許多方面不同于會話?Bean。實體?Bean?是持久的,可以同時由多個客戶端訪問,具有主鍵,而且可以參加與其他實體?Bean?的關系。?
實體?Bean?具有以下特征:?
提供數據庫中數據的對象視圖。?
允許多個用戶進行共享訪問。?
利用?Bean?管理持久性或容器管理持久性,可以持續所有客戶端所需要的時間長度。?
透明地幸免于服務器崩潰而不丟失信息。?
表現數據庫中的共享數據。?
采用實體?Bean?的一個良好情形包括與數據庫、文檔和其他業務對象進行封裝嚴密的事務性持久交互。
容器
實體?Bean?依靠?Enterprise?Bean?管理安全性、并發性、事務處理以及實體?Bean?管理的實體對象的其他容器特有服務。多個客戶端可以并發訪問一個實體對象,而容器可以通過事務處理透明地處理并發訪問。?
每個實體都有一個唯一對象標識符。例如,客戶實體?Bean?可能按客戶編號識別。此唯一標識符或主鍵使客戶端能夠查找某個實體?Bean。
與會話?Bean?一樣,實體?Bean?可以通過使用部署描述符設置其事務處理屬性的方法內的?JDBC?調用訪問數據庫。容器支持下節講述的?Bean?管理和容器管理持久性。
持久性
由于實體?Bean?的狀態存儲在一個有點可持續的存儲區中,因而實體?Bean?是持久的。持久性指實體?Bean?的狀態存在時間超過應用程序或服務器進程的壽命。?
實體?Bean?的持久性可由?Bean?明確執行,并由?Bean?開發者進行編程。這稱為?Bean?管理持久性?(BMP)。?
也可以利用?Sun?Java?System?應用服務器和?Enterprise?Bean?的持久性管理把持久性管理委托給容器。此方法稱為容器管理持久性?(CMP)。在?CMP?機制中,需要使用與?Sun?Java?System?應用服務器集成的持久性管理器來確保可靠的持久性。有關容器管理持久性的其他信息,請參閱“將容器管理持久性用于實體?Bean”。
下圖顯示持久性在?Sun?Java?System?應用服務器環境中的工作方式。
?
有關如何為您的應用程序選擇最適當持久性方法的準則,請參閱“確定實體?Bean?使用”。?
本節介紹以下主題:
Bean?管理持久性?
容器管理持久性?
Bean?管理持久性
在?Bean?管理持久性中,Bean?負責自己的持久性。您所編寫的實體?Bean?代碼包含訪問數據庫的調用。
您通過直接在?Bean?類方法中提供數據庫訪問調用?-?通過?JDBC?和?SQL,對?Bean?管理實體?Bean?進行編碼。數據庫訪問調用必須在?ejbCreate、ejbRemove、ejbFindXXX、ejbLoad?和?ejbStore?方法中。此方法的優點是可以毫不費盡地把這些?Bean?部署到應用服務器。缺點是數據庫訪問非常昂貴,而且在某些情況下,應用服務器能夠比應用編程人員更好地優化數據庫訪問。另外,Bean?管理持久性需要開發人員編寫?JDBC?代碼。
有關使用?JDBC?操作數據的詳細信息,請參閱?Sun?Java?System?應用服務器J2EE?特性和服務開發者指南。
容器管理持久性
在容器管理持久性方面,Enterprise?Bean?容器通過利用持久性管理器進行交互,處理實體?Bean?所需的一切數據庫訪問。Bean?代碼不包含任何數據庫訪問?(JCBC)?調用。因此,Bean?代碼沒有捆綁到特定持久性存儲機制(數據庫)。由于具有此靈活性,即使在不同數據庫上重新部署同一實體?Bean,也不需要修改?Bean?代碼。簡言之,實體?Bean?更具可移植性。?
Bean?開發人員提供抽象?Bean?類。一般來說,容器管理持久性運行時生成知道如何(在?ejbLoad?和?ejbStore?方法中)加載和保存?Bean?狀態的具體實施類。?
要生成數據訪問調用,容器需要您在實體?Bean?的抽象架構中提供的信息。有關抽象架構的其他信息,請參閱“抽象架構”。
只讀?Bean
只讀?bean?是一個從不會被?EJB?客戶端修改的實體?Bean。只讀?Bean?表示的數據可能由其他?Enterprise?Bean?或通過其他手段(如直接數據庫更新)從外部進行更新。
--------------------------------------------------------------------------------
注意??就?Sun?Java?System?應用服務器的這個版本而言,只能把使用?Bean?管理持久性的實體?Bean?指定為只讀。
?
--------------------------------------------------------------------------------
![]()
![]()
![]()
只讀?Bean?最適合于基本數據從不變化或極少變化的情形。有關創建只讀?Bean?的說明,請參閱“使用只讀?Bean”。
開發實體?Bean?
--------------------------------------------------------------------------------
![]()
創建實體?Bean?時,必須提供許多類文件。下列主題中將討論所需執行的任務:
確定實體?Bean?使用?
Bean?開發人員的責任?
定義主鍵類?
定義遠程接口?
定義本地接口?
創建?Bean?類定義(適用于“Bean?管理持久性)?
確定實體?Bean?使用
如果 Bean?表示一個業務實體,而不是一個過程,而且?Bean?的狀態必須是持久的(如果關閉服務器,數據庫中仍然存在?Bean?的狀態),很可能就應使用實體?Bean。
與會話?Bean?不同的是,實體?Bean?實例可同時由多個客戶端進行訪問。容器負責同步使用事務處理的實例狀態。由于此責任是委托給容器執行的,因而您不需要考慮來自多個事務的并發訪問方法。?
您所選擇的持久性方法也有影響:
Bean?管理持久性?-?當您實施一個實體?Bean?管理其自己的持久性時,您直接在?EJB?類方法中實施持久性代碼(例如?JDBC?調用)。缺點是會喪失移植性(即將?Bean?與特定數據庫關聯的風險)。?
容器管理持久性?-?如果實體?Bean?持久性是由容器管理的,容器就透明地管理持久性狀態。不需要在?Bean?方法中實施任何數據訪問代碼。此方法不僅更容易實施,而且可以把?Bean?移植到到不同數據庫。有關實施準則,請參閱“將容器管理持久性用于實體?Bean”。?
Bean?開發人員的責任
本節講述您需要做什么工作才能確保可以把具有?Bean?管理持久性的實體?Bean?部署在?Sun?Java?System?應用服務器上。?
實體?Bean?開發人員負責提供以下類文件:?
主鍵類?
實體?Bean?遠程接口和遠程home接口?-?如果實體?Bean?提供一個遠程客戶端視圖的話?
實體?Bean?本地接口和本地home接口?-?如果實體?Bean?提供一個本地客戶端視圖的話?
實體?Bean?類?
定義主鍵類?
EJB?體系架構使主鍵類可以成為屬于?RMI - IIOP?中合法“值類型”的任何類。此類必須能夠適當實施?hashCode?和相等(其他對象)方法。?主鍵類可以是實體?Bean?所特有,即每個實體?Bean?類可以為其主鍵定義一個不同的類,但是,多個實體?Bean?可以使用同一主鍵類。
您必須在部署描述符中指定一個主鍵類。?
定義遠程接口
本節討論以下主題:
創建遠程home接口?
創建遠程接口?
創建遠程home接口
作為一個?Bean?開發者,您必須提供?Bean?的遠程home接口(如果適用的話)。home接口定義使一個訪問應用程序的客戶端能夠創建、查找和刪除實體對象方法。您創建的遠程home接口必須符合以下要求:?
接口必須擴展?javax.ejb.EJBHome?接口。?
此接口中定義的方法必須遵循?RMI - IIOP?的規則。這就意味著這些方法的參數和返回類型必須具有?RMI - IIOP?的有效類型,而且其? throws ?子句包括?java.rmi.RemoteException。?
遠程home接口中定義的每個方法都必須屬于以下情況之一:?
創建方法。?
遠程home接口必須始終包括?findByPrimaryKey?方法,該方法始終是單對象查找程序。此方法必須把主鍵類聲明為方法參數。?
查找程序方法。?
主方法。假定主方法與創建、查找和刪除方法名稱不一致,主方法就可以具有任意名稱。實體?Bean?類中指定的匹配?ejbHome?方法必須具有同樣的參數數目和類型,并且必須返回與主方法在?Bean?的遠程home接口中指定的主方法相同的類型。?
遠程創建方法
必須把每個創建方法命名為?createXXX,其中?XXX?為匹配?Enteprise?Bean?類中定義的?ejbCreateXXX?方法之一的唯一方法名稱擴展。例如,createEmployee(
),?createLargeOrder(
.)。?
Bean?中的匹配?ejbCreateXXX?必須具有同樣參數數目和類型。但是,返回類型是不同的。?
createXXX?方法的返回類型必須是實體?Bean?遠程接口類型。?
必須把?Enterprise?Bean?類的匹配?ejbCreateXXX?和?ejbPostCreateXXX?方法的? throws ?子句中定義的所有異常包括在遠程home接口的匹配創建方法的? throws ?子句中(即,為創建方法定義的異常集必須是為?ejbCreateXXX?和?ejbPostCreateXXX?方法定義的異常集合的超集)。?
創建方法的? throws ?子句必須包括?javax.ejb.CreateException。?
遠程查找方法
一個home接口可以定義一個或多個查找方法。必須把每個方法命名為?findXXX,其中?XXX?為唯一方法名稱擴展。例如,findApplesAndOranges。?
每個查找程序方法必須與實體?Bean?類定義中定義的其中一個查找程序方法相對應。?
數目和參數類型也必須與?Bean?類中的查找程序方法定義相對應。?
查找? < METHOD > ?方法的返回類型必須是實體?Bean?的遠程接口類型(適用于單對象查找程序)或其中一個集合(適用于多對象查找程序)。?
必須把實體?Bean?類的?ejbFind?方法的? throws ?子句中定義的所有異常包括在遠程home接口的匹配查找方法的? throws ?子句中。?
查找程序方法的? throws ?子句必須包括?javax.ejb.FinderException。?
findByPrimaryKey?方法?
每個遠程home接口必須始終包括?findByPrimaryKey?方法,該方法始終是一個單對象查找程序。?
![]()
該方法必須把主鍵類聲明為方法參數。?
必須把實體?Bean?類的?ejbFindByPrimaryKey?方法的? throws ?子句中定義的所有異常都包括在遠程home接口的匹配查找方法的? throws ?子句中。?
findByPrimaryKey?方法的? throws ?子句必須包括?javax.ejb.FinderException。?
遠程刪除方法
所有home接口都自動(通過擴展?javax.ejb.EJBHome)定義兩個?remove?方法,用來毀壞不再需要的?Enterprise?Bean:
public ? void ?remove(java.lang.Object?primaryKey)?
throws ?java.rmi.RemoteException,?RemoveException?
public ? void ?remove(Handle?handle)?
throws ?java.rmi.RemoteException,?RemoveException?
--------------------------------------------------------------------------------
注意??不要覆蓋這些?remove?方法。
?
--------------------------------------------------------------------------------
![]()
![]()
![]()
遠程home接口示例?
import ?javax.ejb. * ;?
import ?java.rmi. * ;
public ? interface ?MyEntityBeanLocalHome?
??? extends ?EJBHome
![]()
{
??? /**?*/ /**
??????*?Create?an?Employee
??????*? @param ?empName?Employee?name
??????*? @exception ?CreateException?If?the?employee?cannot?be?
?????????created?
?????????*? @return ?The?remote?interface?of?the?bean?
?????? */ ?
??? public ?MyEntity?create(String?empName)?
?????? throws ?CreateException;?
??? /**?*/ /** ?
??????*?Find?an?Employee?
??????*? @param ?empName?Employee?name?
??????*? @exception ?FinderException?if?the?empName?is?not?found?
??????*? @return ?The?remote?interface?of?the?bean?
?????? */ ?
??? public ?MyEntity?findByPrimaryKey(String?empName)?
?????? throws ?FinderException;?
} ?
定義本地接口
要構建一個允許本地方法的?Enterprise?Bean,您必須對本地接口和本地home接口進行編碼。本地接口定義?Bean?的業務方法;本地home接口定義其生命周期(創建 / 刪除)和查找程序方法。
![]()
本節介紹以下主題:
創建本地home接口?
創建本地接口?
創建本地home接口?
home接口定義使使用應用程序的客戶端能夠創建和刪除實體?Bean?的方法。一個?Bean?的本地home接口定義使本地客戶端可以創建、查找和刪除?EJB?對象以及不是?Bean?實例特有的主業務方法(會話?Bean?不具有查找程序和主業務方法)。本地home接口由您定義,并由容器進行實施。客戶端使用?JNDI?查找一個?Bean?的?home。?
本地home接口使客戶端可以:
在home內創建新的實體對象?
在home內查找現有實體對象?
從home刪除實體對象?
執行主業務方法?
本地home接口始終擴展?javax.ejb.EJBLocalHome。例如:?
??? import ?javax.ejb. * ;?
??? public ? interface ?MyEntityLocalBeanHome? extends ?EJBLocalHome?
{?
??????MyEntityLocalBean?create()? throws ?CreateException;?
???} ?
創建本地接口
如果某個實體?Bean?是一種容器管理關系的目標,該實體?Bean?必須具有本地接口。關系的方向確定某個?Bean?是否是一個目標。由于實體?Bean?需要本地訪問,因此,參加容器管理關系的實體?Bean?必須駐留在同一?EJB?JAR?文件中。此本地性的主要優點是提高了性能?-?本地調用比遠程調用快。
由于本地接口遵循?pass?by?reference?語義,您必須明白可以共享通過本地接口傳遞的對象。尤其是,注意不要把一個?Enterprise?Bean?的狀態指定為另一個?Enterprise?Bean?的狀態。您還必須小心確定在本地接口之間傳遞哪些對象,尤其是在交易或安全內容發生變化的情況下。?
接口必須擴展?javax.ejb.EJBLocalHome?接口。?
本地home接口上的方法的?? throws ?子句不得包括?java.rmi.RemoteException。?
本地home接口中定義的每個方法必須是以下方法之一:??
創建方法?
查找程序方法?
home方法?
(本地)創建方法?
必須將每個創建方法命名為?createXXX,其中?XXX?是一個唯一方法名稱的附加部分,而且必須匹配?Enteprise?Bean?類中定義的?ejbCreateXXX?方法之一。例如,createEmployee(
),?createLargeOrder(
.)。?
Bean?中的匹配?ejbCreateXXX?必須具有其參數的同樣數目和類型(請注意,返回類型是不同的。)?
createXXX?方法的返回類型必須是實體?Bean?的本地接口類型。?
必須在遠程接口的匹配?create?方法的? throws ?子句中定義?Enterprise?Bean?類匹配?ejbCreateXXX?和?ejbPostCreateXXX?方法? throws ?子句中定義的所有異常(即,為創建方法定義的異常集必須是為?ejbCreateXXX?和?ejbPostCreateXXX?方法定義的異常集合的超集)。?
創建方法的? throws ?子句必須包括?javax.ejb.CreateException。?
(本地)查找方法?
home接口可以定義一個或多個查找方法。必須將每個方法命名為?findXXX,其中?XXX?是唯一方法名稱擴展。例如,findApplesAndOranges。?
每個查找程序方法必須與實體?Bean?類定義中定義的其中一個查找程序方法相對應。?
數目和參數類型也必須與?Bean?類中的查找程序方法定義相對應。?
查找? < METHOD > ?方法的返回類型必須是實體?Bean?的本地接口類型(適用于單對象查找程序)或其中的一個集合(適用于多對象查找程序)。?
必須將實體?Bean?類的?ejbFind?方法的? throws ?子句中定義的所有異常包括在遠程home接口的匹配查找方法的? throws ?子句中。?
查找程序方法的? throws ?子句必須包括?javax.ejb.FinderException。?
findByPrimaryKey?方法?
每個本地home接口必須始終包括?findByPrimaryKey?方法,該方法始終是一個單對象查找程序。?
方法必須把主鍵類聲明為方法參數。?
必須把實體?Bean?類的?ejbFindByPrimaryKey?方法的? throws ?子句中定義的所有異常包括在遠程home接口的匹配查找方法的? throws ?子句中。?
findByPrimaryKey?方法的? throws ?子句必須包括?javax.ejb.FinderException。?
(本地)home方法?
假如主方法與創建、查找和刪除方法名稱不一致,主方法就可以具有任意名稱。?
實體?Bean?類中指定的匹配?ejbHome?方法必須具有同樣的參數數目和類型,并且必須返回像?Bean?的本地home接口中指定的主方法一樣的類型。?
創建遠程接口?
除了您在遠程接口中定義的業務方法之外,EJBObject?接口定義使您能夠執行以下操作的多種抽象方法:?
檢索?Bean?的home接口?
檢索?Bean?的句柄?-?檢索?Bean?的主鍵,該主鍵唯一識別?Bean?的實例?
將該?Bean?與另一個?Bean?進行對比,看是否相同?
刪除不再需要的?Bean?
有關這些內置方法以及如何使用這些方法的詳細信息,請參閱?Enterprise?JavaBeans?Specification? 2.0 。?
--------------------------------------------------------------------------------
注意??Enterprise?JavaBeans?Specification? 2.0 ?允許?Bean?類實施遠程接口的方法,但是建議不要這樣做,以免無意中通過此方法將一個直接引用傳遞給客戶端,因而破壞??Enterprise?JavaBeans?Specification? 2.0 ?所要求的客戶端 - 容器 - EJB?協議。
?
--------------------------------------------------------------------------------
![]()
![]()
![]()
![]()
實體?Bean?的遠程接口定義一個用戶對于?Bean?的方法的訪問權限。?
接口必須擴展?javax.ejb.EJBObject?接口。?
遠程接口中定義的方法必須遵循?RMI - IIOP?的規則。?
這意味著其參數和返回值類型必須是?RMI - IIOP?的有效類型,而且其? throws ?子句必須包括?java.rmi.RemoteException。?
至于遠程接口中定義的每個方法,實例?Bean?的類中必須有一個匹配的方法。此匹配方法必須具有同一名稱、同樣的參數數目和類型以及同一返回類型。?
必須在遠程接口方法? throws ?子句中定義?Enterprise?Bean?類匹配方法? throws ?子句中定義的異常。?
遠程接口方法不得公開本地接口類型、本地home接口類型或作為參數或結果用于具有容器管理持久性的托管集合類。?
遠程接口示例?
以下片段是一個遠程接口示例:
import ?javax.ejb. * ;?
import ?java.rmi. * ;?
public ? interface ?MyEntity?
??? extends ?EJBObject?
???
{?
??? public ?String?getAddress()? throws ?RemoteException;
??? public ? void ?setAddress(String?addr)? throws ?RemoteException;
} ?
創建?Bean?類定義(適用于?Bean?管理持久性)
對于使用?Bean?管理持久性的實體?Bean,必須把?Bean?類定義為? public ,而且不能是? abstract 。Bean?類必須實施?javax.ejb.EntityBean?接口。例如:
import ?java.rmi. * ;
import ?java.util. * ;
import ?javax.ejb. * ;
public ? class ?MyEntityBean? implements ?EntityBean?
{
??? // ????Entity?Bean?implementation.?These?methods?must?always?be?
???included.
??? public ? void ?ejbActivate()?
{
???}
![]()
??? public ? void ?ejbLoad()?
{
???}
![]()
??? public ? void ?ejbPassivate()?
{
???}
![]()
??? public ? void ?ejbRemove()?
{
???}
![]()
??? public ? void ?ejbStore()?t
{
???}
![]()
??? public ? void ?setEntityContext(EntityContext?ctx)?
{
???}
![]()
??? public ? void ?unsetEntityContext()?
{
???}
??? // ?other?code?omitted?here
.
???} ?
除了這些方法之外,實體?Bean?類還必須定義一個或多個?ejbCreate?方法和?ejbFindByPrimaryKey?查找程序方法。實體?Bean?類可以隨意為每個?ejbCreate?方法定義一個?ejbPostCreate。實體?Bean?類可以提供開發人員定義的額外的查找程序方法,這些方法形式為?ejbFindXXX,其中?XXX?表示一個唯一的方法名稱擴展(例如,ejbFindApplesAndOranges),該擴展與任何其他方法名稱不相重復。
實體?Bean?一般實施一個或多個業務方法。這些方法通常對于每個?Bean?都是唯一的,并且代表其特定功能。業務方法名稱可以是任何事情,但不得與?EJB?體系架構中使用的方法名稱相沖突。必須將業務方法聲明為? public 。方法參數和返回值類型必須是合法?Java?RMI。 throws ?子句可以定義應用程序特有的異常,并且可以包括?java.rmi.RemoteException。
有兩種在實體?Bean?中實施的業務方法類型:?
內部方法?-?由其他業務方法在?Bean?中使用,但從不在?Bean?本身的外部訪問。?
外部方法?-?由實體?Bean?的遠程接口引用。?
以下各節介紹實體?Bean?類定義中的各種方法:?
使用?ejbCreate?
使用?ejbActivate?和?ejbPassivate?
使用?ejbLoad?和?ejbStore?
使用?setEntityContext?和?unsetEntityContext?
使用?ejbRemove?
使用查找程序方法?
使用?ejbCreate
實體?Bean?必須實施一個或多個?ejbCreate?方法。針對允許客戶端調用?Bean?的每種方式,都必須有一個方法。例如:
public ?String?ejbCreate(String?orderId,?String?customerId,
???String?status,? double ?totalPrice)
??? throws ?CreateException?
{
?????? try ?
{
??????InitialContext?ic? = ? new ?InitialContext();
??????DataSource?ds? = ?(DataSource)?ic.lookup(dbName);
??????con? = ?ds.getConnection();
??????String?insertStatement? =
????????? " insert?into?orders?values?(???,???,???,???) " ;
??????PreparedStatement?prepStmt? =
?????????con.prepareStatement(insertStatement);
??????prepStmt.setString( 1 ,?orderId);
??????prepStmt.setString( 2 ,?customerId);
??????prepStmt.setDouble( 3 ,?totalPrice);
??????prepStmt.setString( 4 ,?status);
??????prepStmt.executeUpdate();
??????prepStmt.close();
???} ? catch ?(Exception?ex)?
{
?????? throw ? new ?CreateException( " ejbCreate:? " ?
????????? + ex.getMessage());
???}
} ?
public ?String?ejbPostCreate(String?orderId,?String?customerId,String
status,? double ?totalPrice)?
??? throws ?CreateException?
![]()
{?
?
?
} ?
必須將每個?ejbCreate?方法聲明為? public ,?每個?ejbCreate?方法必須返回主鍵類型,而且必須命名為?ejbCreate。返回類型可以是出于鍵的目的轉換為一個數字的任何合法?Java?RMI?類型。所有參數都必須是合法?Java?RMI?類型。 throws ?子句可以定義應用程序特有的異常,并且可以包括?java.ejb.CreateException。
這是用以建立關系的方法。對于每個?ejbCreate?方法,實體?Bean?類可以定義一個相應?ejbPostCreate?方法來處理立即跟蹤創建的實體服務。必須將每個?ejbPostCreate?方法聲明為? public ,每個?ejbPostCreate?方法必須返回空白,并且命名為?ejbPostCreate。方法參數(如果有的話)必須在數目和參數類型方面匹配其相應的?ejbCreate?方法。 throws ?子句可以定義應用程序特有的異常,而且可以包括?java.ejb.CreateException。
使用?ejbActivate?和?ejbPassivate
當一個服務器應用程序需要每個實體?Bean?實例時,該?Bean?的容器調用?ejbActivate?準備好一個要使用的?Bean?實例。同樣地,如果不再需要某個實例,該?Bean?的容器就調用?ejbPassivate,取消該?Bean?與應用程序之間的關聯。?
如果在首次將一個?Bean?準備好供某個應用程序使用時或不再需要某個?Bean?時,需要執行特定應用程序任務,您應在?ejbActivate?和?ejbPassivate?方法內編寫這些操作的程序。例如,您可以在?ejbPassivate?期間發布對數據庫和后臺資源的應用,以及在?ejbActivate?期間重新獲得它們。
使用?ejbLoad?和?ejbStore
實體?Bean?可以與容器協作,把?Bean?狀態信息存儲在一個數據庫中,以便于執行同步操作。如果是?Bean?管理持久性,您負責對?ejbLoad?和?ejbStore?進行編碼。容器通過在一項事務開始時調用?ejbLoad?以及在事務成功完成時調用?ejbStore,確保?Bean?的狀態與數據庫同步。?
使用您的?ejbStore?實施將數據信息存儲在數據庫中,并使用您的?ejbLoad?實施從數據庫中檢索狀態信息。?
以下示例顯示存儲和檢索活動數據的?ejbLoad?和?ejbStore?方法定義。?
public ? void ?ejbLoad()
?????? throws ?java.rmi.RemoteException
![]()
{
???String?itemId;
???javax.sql.Connection?dc? = ? null ;
???java.sql.Statement?stmt? = ? null ;
???java.sql.ResultSet?rs? = ? null ;
???itemId? = ?(String)?m_ctx.getPrimaryKey();
???System.out.println( " myBean:?Loading?state?for?item? " ? + ?itemId);
???String?query? =
?????? " SELECT?s.totalSold,?s.quantity? " ? +
?????? " ?FROM?Item?s? " ? +
?????? " ?WHERE?s.item_id?=? " ? + ?itemId;
???dc? = ? new ?DatabaseConnection();
???dc.createConnection(DatabaseConnection.GLOBALTX);
???stmt? = ?dc.createStatement();
???rs? = ?stmt.executeQuery(query);
??? if ?(rs? != ? null )?
{
??????rs.next();
??????m_totalSold? = ?rs.getInt( 1 );
??????m_quantity? = ?rs.getInt( 2 );
???}
} ?
public ? void ?ejbStore()
?????? throws ?java.rmi.RemoteException
![]()
{
???String?itemId;
???itemId? = ?(String)?m_ctx.getPrimaryKey();
???DatabaseConnection?dc? = ? null ;
???java.sql.Statement?stmt1? = ? null ;
???java.sql.Statement?stmt2? = ? null ;
???System.out.println( " myBean:?Saving?state?for?item?=? " ? + ?itemId);
???String?upd1? =
?????? " UPDATE?Item? " ? +
?????? " ?SET?quantity?=? " ? + ?m_quantity? +
?????? " ?WHERE?item_id?=? " ? + ?itemId;
???String?upd2? =
?????? " UPDATE?Item? " ? +
?????? " ?SET?totalSold?=? " ? + ?m_totalSold? +
?????? " ?WHERE?item_id?=? " ? + ?itemId;
???dc? = ? new ?DatabaseConnection();
???dc.createConnection(DatabaseConnection.GLOBALTX);
???stmt1? = ?dc.createStatement();
???stmt1.executeUpdate(upd1);
???stmt1.close();
???stmt2? = ?dc.createStatement();
???stmt2.executeUpdate(upd2);
???stmt2.close();
} ?
有關訪問與其他?Bean?并發的事務的?Bean?隔離級別的詳細信息,請參閱?
使用?setEntityContext?和?unsetEntityContext
容器在其創建一個實體?Bean?實例(該實例為?Bean?提供一個連接容器的接口)之后,調用?setEntityContext。實施此方法存儲容器傳遞的實體上下文。隨后,您可以使用此引用獲取該實例的主鍵,等等。?
??? public ? void ?setEntityContext(javax.ejb.EntityContext?ctx)
???
{
???m_ctx? = ?ctx;
???} ?
同樣地,容器調用?unsetEntityContext?從實例中刪除容器引用。這是?Bean?實例成為要刪除的對象之前容器調用的最后一個?Bean?類方法。執行此調用之后,Java?垃圾收集機制最終調用實例上的?finalize?將其清除,并加以處置。
??? public ? void ?unsetEntityContext()
???
{
???m_ctx? = ? null ;
???} ?
使用?ejbRemove
客戶端可以調用實體?Bean?的home接口或組件接口上的刪除方法,從數據庫中刪除相關記錄。容器調用某個實體?Bean?實例上的?ejbRemove?方法,響應實體?Bean?的home接口或組件接口上的客戶端調用,或者作為?cascade - delete?操作的結果。?
使用查找程序方法
由于實體?Bean?具有持久性、可在客戶端之間共享,可擁有不只一個同時實例化的實例,因此,一個實體?Bean?必須實施至少一個?ejbFindByPrimaryKey?方法。這使客戶端和容器能夠查找特定?Bean?實例。所有實體?Bean?必須提供一個唯一主鍵,作為一個識別簽名。在?Bean?的類中實施?ejbFindByPrimaryKey?方法,使一個?Bean?能夠將其主鍵返回到容器。?
下面的示例顯示?FindByPrimaryKey?的一個定義:?
public ?String?ejbFindByPrimaryKey(String?key)
?????? throws ?java.rmi.RemoteException,
?????????javax.ejb.FinderException?
在某些情況下,您根據?Enterprise?Bean?的作用、根據實例所使用的某些值或根據其他條件,查找特定實體?Bean?實例。這些針對實施的查找程序方法名稱的形式為?ejbFindXXX,其中?XXX?表示一個不重復任何其他方法名稱(例如,ejbFindApplesAndOranges)的方法名稱的唯一擴展。?
必須將查找程序方法聲明為? public ?,而且其參數以及返回值必須為合法?Java?RMI?類型。每個查找程序方法返回類型必須是實體?Bean?的主鍵類型或具有同一主鍵類型的對象的集合。如果返回類型為一個集合,返回類型必須是以下兩項之一:
JDK? 1.1 ?java.util.Enumeration?接口?
Java? 2 ?java.util.Collection?接口?
查找程序方法的? throws ?子句是一個應用程序特有的異常,而且可能包括?java.rmi.RemoteException?和 / 或?java.ejb.FinderException。
使用只讀?Bean?
--------------------------------------------------------------------------------
![]()
只讀?Bean?是一種?EJB?客戶端從不修改的實體?Bean。只讀?Bean?表現的數據可以由其他?Enterprise?Bean?從外部進行更新,也可以通過其他手段更新,如直接數據庫更新。
--------------------------------------------------------------------------------
注意??對于此版?Sun?Java?System?應用服務器,只能把使用?Bean?管理持久性的實體?Bean?指定為只讀。
只讀?Bean?為?Sun?Java?System?應用服務器所特有,而且不是?Enterprise?JavaBeans?Specification? 2.0 ?的組成部分。
?
--------------------------------------------------------------------------------
![]()
![]()
![]()
本節介紹以下主題:
只讀?Bean?特征和生命周期?
只讀?Bean?良好做法?
刷新只讀?Bean?
部署只讀?Bean?
只讀?Bean?特征和生命周期
只讀?Bean?最適合于基本數據從不變化或極少變化的情形。例如,只讀?Bean?可用來表示某個公司的股票價格(外部更新)。在此情況下,使用常規實體?Bean?可能會增加調用?ejbStore?的負擔,使用只讀?Bean?就可以避免這種情況。
只讀?Bean?具有以下特征:
只有實體?Bean?可以是只讀?Bean。?
僅允許?Bean?管理持久性。?
僅允許容器管理事務;只讀?Bean?無法啟動其自己的事務。?
只讀?Bean?不更新任何?Bean?狀態。?
ejbStore?從不由容器調用。?
只有在調用事務方法時,或最初(在緩存)中創建?Bean?時,或在?Bean?的?refresh - period - in - seconds?控制的定期間隔時,才調用?ejbLoad。?
home接口可以擁有任意數目的查找方法。查找方法的返回類型必須是同一?Bean?類型的主鍵(或一個主鍵集合)。?
如果?Bean?代表的數據可以更改,則必須將?refresh - period - in - seconds?設置為按定期間隔刷新。ejbLoad?是按定期間隔調用的。?
只讀?Bean?使用適當查找方法而存在。?
只讀?Bean?被緩存起來,并具有與實體?Bean?相同的緩存屬性。當選擇只讀?Bean?作為在緩存中騰出空間的犧牲者時,就調用?ejbPassivate,并將?Bean?返回到自由池。在自由池時,Bean?不具有任何標識,并將僅用于作為任何查找程序請求。?
只讀?Bean?被捆綁到像讀寫實體?Bean?這樣的命名服務,而且客戶端可以用查找讀寫實體?Bean?一樣的方法查找只讀?Bean。?
只讀?Bean?良好做法
避免home接口中有任何?create?或?remove?方法?
將任何有效的?EJB? 2.0 ?事務屬性用于方法事務屬性?
擁有?TX_SUPPORTED?的理由是可以在同一事務中讀取未授權的數據。而且,TX?屬性可用于強制?ejbLoad。?
刷新只讀?Bean
刷新只讀?Bean?的方法有多種,它們在以下各節中進行討論:
調用事務方法?
定期刷新?
已編程方式刷新?
調用事務方法?
調用任何事務方法將會調用?ejbLoad。?
定期刷新?
通過在?Sun?Java?System?應用服務器特有的?XML?文件中指定?refresh - period - in - seconds?元素,可以定期刷新只讀?Bean。?
如果在?refresh - period - in - seconds?中指定的值為零,就從不刷新?Bean(除非訪問某個事務方法)。?
如果值大于零,則按指定頻率刷新?Bean。?
--------------------------------------------------------------------------------
注意??如果可在?Sun?Java?System?應用服務器之外修改數據,這就是刷新?Bean?狀態的唯一方法。?
?
--------------------------------------------------------------------------------
![]()
![]()
![]()
以編程方式刷新?
一般情況下,更新只讀?Bean?緩存的任何數據的?Bean?需要通知只讀?Bean?刷新其狀態。您可以使用?ReadOnlyBeanNotifier?來強制刷新只讀?Bean。為此,在?ReadOnlyBeanNotifier?Bean?上調用以下方法:
??? public ? interface ?ReadOnlyBeanNotifier?
?????? extends ?java.rmi.Remote?
???
{?
??????refresh(Object?PrimaryKey)?
????????? throws ?RemoteException;?
???} ?
容器提供對?ReadOnlyBeanNotifier?接口的實施。用戶可以使用以下代碼片段查找?ReadOnlyBeanNotifier:?
com.sun.ejb.ReadOnlyBeanNotifier?notifier? = ?com.sun.ejb.containers.ReadOnlyBeanHelper.getReadOnlyBeanNotifier
???( < ejb - name - of? - the - target > );?
???notifier.refresh( < PrimaryKey > );?
更新只讀?Bean?緩存的任何數據的?Bean?需要調用?refresh?方法。下一次調用只讀?Bean?的(非事務性)調用時,就會調用?ejbLoad。?
部署只讀?Bean?
只讀?Bean?是用與其他實體?Bean?相同的方式部署的。但是,在?Sun?Java?System?應用服務器特有的?XML?文件中的?Bean?的輸入中,必須把?is - read - only - bean?元素設置為?True(真)。也就是:
< is - read - only - bean > true </ is - read - only - bean >
![]()
另外,可以把?refresh - period - in - seconds?元素設置為指定刷新?Bean?的頻率的某些值。如果丟失此元素,就假定?? 600 (秒)默認值。?
具有相同事務上下文的所有請求都被路由到同一只讀?Bean?實例。部署者可以通過將?allow - concurrent - access?元素設置為真(允許同時方法)或?False(假)(將并發訪問序列化為同一只讀?Bean),指定是否必須序列化這么多請求。?
有關這些元素的詳細信息,請參閱?Sun?Java?System?應用服務器管理員配置文件參考。
處理并發訪問的同步?
--------------------------------------------------------------------------------
![]()
作為一名實體?Bean?開發者,您一般不需要考慮從多個事務并發訪問一個實體?Bean。在這些情況下,該?Bean?的容器自動提供同步。在?Sun?Java?System?應用服務器中,容器針對每個同時發生并使用?Bean?的事務,激活一個實體?Bean。?
事務同步是由基本數據庫在數據庫訪問調用期間自動執行的。您一般與基本數據庫或資源一起執行此同步。一種方法是在?ejbLoad?方法中獲得相應數據庫鎖定,例如通過選擇適當隔離級別或通過使用一個用于?update?子句的?select。具體情況取決于所使用的數據庫。?
有關詳細信息,請參閱?Enterprise?JavaBeans?Specification? 2.0 ,因為該規范與并發訪問相關
![]()
posted on 2007-01-18 17:51 youngturk 閱讀(292) 評論(0) 編輯 收藏 所屬分類: 關于EJB學習