實體bean 實體bean的角色 實體bean用來代表底層的對象。最常用的是用實體bean代表關系庫中的數據。一個簡單的實體bean可以定義成代表數據庫表的一個記錄,也就是每一個實例代表一個特殊的記錄。更復雜的實體bean可以代表數據庫表間關聯視圖。在實體bean中還可以考慮包含廠商的增強功能,如對象--關系映射的集成。 通常用實體類代表一個數據庫表比代表多個相關聯的表更簡單且更有效。反過來可以輕易地向實體類的定義中增加關聯,這樣可以最大地復用cache並減小舊數據的表現。 實體bean和對話bean的比較 看起來會話bean好象沒什麼用處,尤其對於數據驅動的應用程序。當然事實並不是這樣。因為實體bean(譬如說)代表底層數據庫的一行,則實體bean實例和數據庫記錄間就是一對一的關系。因為多個客戶端必須訪問底層記錄,這意味著,不同於會話bean,客戶端必須共享實體bean。因為是共享的,所以實體bean不允許保存每個客戶端的信息。會話bean允許保存客戶端的狀態信息,客戶端和會話bean實例間是一對一的。實體bean允許保存記錄的信息,實體bean實例和記錄間是一對一的。一個理想的情況是客戶端通過會話bean連接服務器,然後會話bean通過實體bean訪問數據庫。這使得既可以保存客戶端的信息又可以保存數據庫記錄的信息。 同時會話bean也不能提供在相同或不同的EJB類調用間進行全局的事務控制。沒有會話bean,應用程序開發者(客戶端開發者)就必須理解EJB類的事務要求,並使用客戶端的事務劃分來提供事務控制。EJB的主要好處就是應用開發者不需知道EJB類的事務需求。一個會話bean可以代表一個商業操作,進行事務控制,不需要客戶端進行事務劃分。 Finder方法 通過home或remote interface創建和刪除bean的實例,對實體bean和會話bean來說有不同的含義。對會話bean來說,刪除意味著從容器中刪除,不能再使用,並且其狀態信息也丟失了。對於實體bean,刪除意味著底層數據庫記錄被刪除了。因此,一般不把刪除作為實體bean生命周期的一部分。 創建一個實體bean意味著一個記錄被插進數據庫中。與刪除操作類似,創建操作通常也不作為實體bean生命周期的一部分。客戶端訪問實體bean需要先找到它。除了create()方法,一個實體bean的home interface還有finder方法。客戶端需要根據應用程序的限制來識別一個特殊的數據庫記錄。例如: public interface AccountHome extends EJBHome { public Account findByFirstLast(String first, String last) throws RemoteException,FinderException; public Account findByAccountNumber(String acctNum) throws RemoteException,FinderException; } 當客戶端調用home object的任何方法,容器把調用傳遞到實體bean的相應方法中。 Public class myEntityBean implements EntityBean { … public Obejct ejbFindByFirstLast(String first, String last) { //runs appropriate singleton SELECT statement //returns primary key for selected row } public Obejct ejbFindByAccountNumber(String acctNum) { //runs appropriate singleton SELECT statement //returns primary key for selected row } } 一個較好的方法是把finder方法當成數據庫的SELECT語句,而動態SQL參數相當於方法的參數。注意home interface中的finder方法向客戶端返回一個對EJBObject的遠程引用。Bean中的Finder方法向容器返回一個唯一的標識符,稱為主鍵。容器用這個主鍵實例化一個代表選定的記錄的EJBObject。不論如何實現finder方法,容器都用這個主鍵代表這個選定的記錄,由實體類來決定如何用唯一的標識符來代表記錄。 由可能一個finder方法得到滿足SELECT語句條件的多個記錄。這種情況下bean的finder方法返回一個主鍵的枚舉類型。Home interface的Finder方法定義成向客戶端返回EJBObject引用的枚舉類型。 Public interface AccountHome extends EJBHome { … public Enumeration findByCompany(String companyName) throws RemoteException,FinderException; } public class myEntityBean implements EntityBean { … public Enumeration ejbFindByCompany(String companyName) { //runs appropriate SELECT statement //returns an Enumeration of primary keys } } 主鍵 主鍵這個詞有可能被曲解。把它理解為唯一的標識符更恰當些。當實體bean代表一個數據庫記錄時,主鍵可能是該記錄的組合鍵。對於每個實體bean的實例,有一個相應的EJBObject.當一個EJBObject與一個實體bean實例對應時,該實例的主鍵保存在EJBObject中。 這時說該實體bean的實例有一個標識符。當客戶端調用home object的finder方法時,容器會用沒有標識符的實體bean的實例來執行這個請求。容器可能為此維持一個甚至多個匿名的實例。不論如何實現finder方法,都必須向容器返回底層數據的主鍵,如數據庫的記錄。如果多個記錄滿足條件,那麼就返回多個主鍵。當容器得到主鍵後,它會用該主鍵初始化一個EJBObject.容器也可以初始化一個與每個EJBObject關聯的實體bean的實例。因為底層記錄的標識符在EJBObject中保存,因此在bean實例中沒有狀態。因此,容器可以在EJBObject上調用商業方法時再實例化bean,以節省內存資源。 當finder方法向容器返回主鍵時,容器首先會檢查該主鍵的EJBObject是否已經存在。如果該主鍵的EJBObject已經存在,那麼容器不會創建一個新的EJBObject,而是向客戶端返回這個已存在的EJBObject的引用。這樣就保證了每個記錄只有一個EJBObject的實例,所有的客戶端共享EJBObject. 主鍵只是在該類中唯一地標識bean的實例,容器負責保證其范圍。應該明確finder方法只是從數據庫中取出數據的主鍵,而不包含其它的數據項。也可能調用finder方法後不產生任何實體bean的實例,只產生包含該主鍵的EJBObject,當客戶端調用EJBObject的方法時在產生並導入實體bean的實例。 Home object保證客戶端可以訪問以下方法: public myRem findByPrimaryKey(Obejct key) throws …; EJBObject提供以下方法的一個實現: Public Object getPrimaryKey(); 客戶端能在任何時候獲得實體bean的主鍵,並且以後可以使用該主鍵通過home interface重建對實體的引用。主鍵類的類型在部署描述符中指定。Bean開發者可以用任何類類型來表示主鍵。唯一的要求是類必須實現serializable,因為主鍵可能在客戶和服務器間傳遞。