译者前言
有关本章中相应源代码的下载,请参看一个Session Bean的示例
正文
数据是绝大多数商业应用程序的核心。在J2EE应用程序中,entity bean反映了存储在一个数据库中的商业对象。对于使用bean管理持续化的entity bean,你必须编写代码以访问数据库。尽管编写这样的代码会增加一些额外的工作量,但是与此同时,你对entity bean如何访问数据库也获得了更多的控制。
在这一章中,我们将讨论一个使用bean管理持续化的entity bean的编程问题。对于entity beans的相关概念,请参阅Entity Bean是什么?.
SavingsAccountEJB示例
在这一部分的这个entity bean表现了一个简单的银行帐户。SavingsAccountEJB的状态存储在一个关系型数据库的savingsaccount表中。savingsaccount表是用下面的SQL语句建立的:
CREATE TABLE savingsaccount
(id VARCHAR(3)
CONSTRAINT pk_savingsaccount PRIMARY KEY,
firstname VARCHAR(24),
lastname VARCHAR(24),
balance NUMERIC(10,2));
SavingsAccountEJB示例需要以下代码:
1、Entity bean类(SavingsAccountBean)
2、Home接口(SavingsAccountHome)
3、Remote接口(SavingsAccount)
此外,这个示例还用到以下类:
1、一个名为InsufficientBalanceException的功能类
2、一个名为SavingsAccountClient的客户端类
在j2eetutorial/examples/src/ejb/savingsaccount目录下有这个示例的源代码。要编译这个代码,到j2eetutorial/examples目录下并输入ant savingsaccount。在j2eetutorial/examples/ears下有SavingsAccountApp.ear文件的示例。
Entity Bean类
在示例程序中,entity bean类名为SavingsAccountBean。在你浏览它的代码时,请注意它满足了所有使用bean管理持续化的entity bean的必要条件。首先,它实现了以下几个方面:
1、EntityBean接口
2、零个或多个ejbCreate和ejbPostCreate方法
3、Finder方法
4、商业方法
5、Home方法
另外,一个使用bean管理持续化的entity bean类必须满足这些条件:
1、类定义为public。
2、类不能定义为abstract或final。
3、包含一个空的构造函数。
4、它不能实现finalize方法。
EntityBean接口
EntityBean接口继承自实现了Serializable接口的EnterpriseBean接口。EntityBean接口中声明了许多方法,例如ejbActivate和ejbLoad,这些方法你必须在你的entity bean类中加以实现。我们将在下面对这些方法作详细讨论。
ejbCreate方法
当客户端调用create方法时,EJB容器调用相应的ejbCreate方法。典型的情况是,一个entity bean中的ejbCreate方法执行以下任务:
1、将实体状态添加到数据库中
2、对实例变量进行初始化
3、返回主键
SavingsAccountBean的ejbCreate方法通过调用private类型的insertRow方法将实体状态添加到数据库中,这样做的结果是执行了一个INSERT语句。下面是ejbCreate方法的源代码:
public String ejbCreate(String id, String firstName,
String lastName, BigDecimal balance)
throws CreateException {
if (balance.signum() == -1) {
throw new CreateException
("A negative initial balance is not allowed.");
}
try {
insertRow(id, firstName, lastName, balance);
} catch (Exception ex) {
throw new EJBException("ejbCreate: " +
[1] [2] [3] 下一页
ex.getMessage());
}
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.balance = balance;
return id;
}
尽管SavingsAccountBean类只有一个ejbCreate方法,但是一个enterprise bean可以包含多个ejbCreate方法。示例请参见j2eetutorial/examples/src/ejb/cart目录下的CartEJB.Java。
在为一个entity bean编写ejbCreate方法,必须遵守以下规则:
1、访问控制修饰必须是public。
2、返回类型必须是主键。
3、参数类型必须满足Java 2 RMI API。
4、方法修饰不能是final或static。
throws子句可以包含javax.ejb.CreateException的你的应用程序中所指定的其它例外。如果输入的参数无效,一个ejbCreate方法通常会抛出一个CreateException。如果因为已经存在另一个相同主键的实体,ejbCreate方法不能建立一个新的实体,它会抛出一个javax.ejb.DuplicateKeyException(CreateException的子类)。如果一个客户端接受到一个CreateException或者是一个DuplicateKeyException,它会认为实体未被建立。
可以通过一个对于J2EE服务器未知的应用程序将一个entity bean的状态直接插入到数据库中。例如,可以使用一个SQL脚本在savingsaccount表中添加一行。尽管对应于这一行的entity bean不是由一个ejbCreate方法创建的,但是客户端程序还是可以对这个bean进行定位。
ejbPostCreate方法
对于每一个ejbCreate方法,你必须在entity bean类中编写一个ejbPostCreate方法。EJB容器在调用ejbCreate方法后会立即调用ejbPostCreate方法。与ejbCreate方法不同,ejbPostCreate方法可以调用EntityContext接口中的getPrimaryKey方法和getEJBObject方法。有关getEJBObject方法的详细信息,请参看传递一个Enterprise Bean的对象索引。不过,你的ejbPostCreate方法常常会是一个空方法。
ejbPostCreate方法必须满足以下条件:
1、参数的数量和类型必须与相应的ejbCreate方法相匹配。
2、访问控制修饰必须是public。
3、方法修饰不能是final或static。
4、返回类型必须是void。
throws子句可以包含javax.ejb.CreateException和你的应用程序中所指定的例外。
ejbRemove方法
一个客户端可以通过调用remove方法删除一个entity bean。这个调用会导致EJB容器调用ejbRemove方法,该方法会从数据库中删除这个实体状态。在SavingsAccountBean类中,ejbRemove方法调用一个名为deleteRow的private方法,这样做的结果是执行了一个DELETE语句。ejbRemove方法的源码比较短:
public void ejbRemove() {
try {
deleteRow(id);
catch (Exception ex) {
throw new EJBException("ejbRemove: " +
ex.getMessage());
}
}
如果ejbRemove方法遇到一个系统问题,它会抛出javax.ejb.EJBException。如果遇到的是一个应用程序错误,它会抛出一个javax.ejb.RemoveException。有关系统例外和应用程序例外的比较。请参看处理例外。
直接使用数据库删除也可以删除一个entity bean。例如,如果一个SQL脚本删除了包含一具entity bean状态的行,相应的entity bean也会被删除。
ejbLoad方法和ejbStore方法
如果EJB容器需要将一个entity bean的实例变量与存储在数据库中的相应的值进行同步,它会调用ejbLoad方法和ejbStore方法。ejbLoad方法会根据数据库中的值刷新实例变量,而ejbStore方法会将实例变量的值写入到数据库中。客户端不能调用ejbLoad方法和ejbStore方法。
如果一个商业方法与一个事务关联,容器会在执行商业方法前调用ejbLoad。而在商业方法执行后,EJB容器会立即调用ejbStore。因为容器会调用ejbLoad和ejbStore,所以你不需要在你的商业方法中刷新和存储实例变量。SavingsAccountBean类依靠容器进行实例变量和数据库的同步。因此,SavingsAccountBean的商业方法必须与事务关联。
如果ejbLoad和ejbStore不能在底层数据库中定位一个实体,它们会抛出javax.ejb.NoSUChEntityException。这个例外是EJBException的一个子例。因为EJBException是RuntimeException的一个子类,所以你不需要在throws语句中包含它。如果NoSuchEntityException被抛出,EJB容器会在将其返回到客户端前将其包装到一个RemoteException中。
上一页 [1] [2] [3] 下一页
在SavingsAccountBean类中,ejbLoad调用了loadRow方法,这样做的结果是执行了一个SELECT语句并将得到的值重新指派给实例变量。ejbStore调用了storeRow方法,这样做的结果是通过一个UPDATE语句将实例变量存储到数据库中。下面是ejbLoad方法和ejbStore方法的源代码:
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。在SavingsAccountClient程序中,可以通过三个finder方法定位entity bean:
SavingsAccount jones = home.findByPrimaryKey("836");
...
Collection c = home.findByLastName("Smith");
...
Collection c = home.findInRange(20.00, 99.00);
对于每一个客户端可用的finder方法,entity bean类都必须实现一个相应的以ejbFind为前缀的方法。例如,在SavingsAccountBean类中,ejbFindByLas
(出处:http://www.sheup.com)
上一页 [1] [2] [3]
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。在SavingsAccountClient程序中,可以通过三个finder方法定位entity bean:
SavingsAccount jones = home.findByPrimaryKey("836");
...
Collection c = home.findByLastName("Smith");
...
Collection c = home.findInRange(20.00, 99.00);
对于每一个客户端可用的finder方法,entity bean类都必须实现一个相应的以ejbFind为前缀的方法。例如,在SavingsAccountBean类中,ejbFindByLas
(出处:http://www.sheup.com/)
上一页 [1] [2] [3] [4]