实体 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,Stringstatus, 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 阅读(276) 评论(0) 编辑 收藏 所属分类: 关于EJB学习
Powered by: BlogJava Copyright © youngturk