实体Bean包含BMP和CMP两种类型。对BMP实体Bean而言,开发者必须提供各自的数据访问逻辑。为了实现BMP,通常会使用操作数据库的API,比如JDBC.对于CMP实体Bean而言,EJB容器会自动实现数据访问逻辑。这就是CMP的优势所在。通常,只有在应用服务器提供的CMP和目标RDBMS不能满足性能要求时,才去考虑BMP.此时,开发者能够细粒度调整BMP的性能。
所有的实体Bean类必须实现javax.ejb.EntityBean接口,包括BMP、CMP.EntityBean接口定义了EJB容器对实体Bean组件进行的回调方法,它还可能含有其他方法,比如创建实体Bean,查找实体Bean.
同ejbCreate()一样,finder方法在Home接口和Bean类中的方法签名不相同:
1、实体Bean实例返回主键给EJB容器,而Home对象返回EJB对象给客户。
2、Bean类和Home类中的finder方法签名,除了Bean类存在ejb前缀外,其他都一样。
finder方法的工作机制:
1、当客户调用Home对象的finder方法时,Home客户请求实体Bean实例,替它查找到符合客户要求的主键。随后,实体Bean实例将返回主键集合给EJB容器。
2、当EJB容器接收到来自实体Bean实例的主键集合时,它将创建EJB对象结合。注意,它会为各个主键创建EJB对象。最后,容器将EJB对象放着在集合中,并返回给客户。随后,可以调用EJB对象中的方法了。每个EJB对象代表了各个实体Bean实例映射的RDBMS数据。
finder方法需遵守如下规则:
1、所有的finder方法必须以ejbFind开始
2、实体Bean组件必须提供ejbFindByPrimarKey方法。通过该方法,能够基于客户提供的主键查找到RDBMS中的唯一记录,并映射到实体Bean实例。由于各个实体Bean都存在主键,因此所有实体Bean的Bean类必须支持ejbFindByPrimaryKey方法。
3、可以提供多个finder方法,而且他们的名字、参数都不一样。因此,EJB客户可以使用各种查找策略,以定位到相应的实体Bean实例集合。
4、查找方法必须返回实体Bean的主键。当然,返回值有可能是单个主键,也可能是主键集合。
package com.testproject.ejb.entity;
import java.rmi.RemoteException;
import javax.ejb.EJBObject;
/**//*
* 客户将通过这一接口同EJB组件进行交互。
* EJB容器会实现这一接口。我们将接口实现称之为EJB对象。
* EJB对象会将请求委派给Bean类。
*/
public interface Account extends EJBObject {
/** *//**
* 将amt存入账户
*/
public void deposit(double amt)throws RemoteException;
/** *//**
* 从银行账户去amount
*/
public void withdraw(double amount)throws RemoteException;
//getter/setter方法,对应于持久化域
public double getBalance()throws RemoteException;
public String getOwnerName()throws RemoteException;
public void setOwnerName(String name)throws RemoteException;
public String getAccountID()throws RemoteException;
public void setAccountId(String id)throws RemoteException;
}
package com.testproject.ejb.entity;
import java.rmi.RemoteException;
import java.util.Collection;
import javax.ejb.CreateException;
import javax.ejb.EJBHome;
import javax.ejb.FinderException;
/** *//**
* Account的Home接口。
* EJB容器负责实现它,我们将这一接口的实现称之为Home对象。
* Home对象充当了EJB对象的工厂。
*/
public interface AccountHome extends EJBHome {
/** *//**
* 此时,我们定义了单个create()方法。
* 对应于AccountBean中的ejbCreate()方法。它负责创建EJB对象。
*/
Account create(String accountID,String ownerName)throws CreateException,RemoteException;
/** *//**
* 通过主键,查找Account
*/
public Account findByPrimaryKey(AccountPK key)throws FinderException,RemoteException;
/** *//**
* 通过账户所有人,来查找他的所有账户
*/
public Collection findByOwnerName(String name)throws FinderException,RemoteException;
/** *//**
* Home业务方法独立于任何帐号,它返回银行帐号的总合。
*/
public double getTotalBankValue()throws RemoteException;
}
package com.testproject.ejb.entity;
import java.io.Serializable;
/** *//**
* 注意:
* 1、主键类含有简单字符串accountID.它能够唯一标识银行账号。
* 2、必须提供toString()方法。EJB容器将调用toString()方法,以获得主键的字符串取值。
* 3、必须提供hashCode()方法。一旦提供了hashCode()方法,就可以将主键类存放到Hashtable中。EJB
* 容器需要hashCode()方法。在容器内部,它可能使用Hashtable或类似结构,以存放内存中的所有实体Bean实例
* 并使用各个主键作为Hashtable的键(key)
* 4、必须提供equals()方法。在容器比较2个缓存的实体Bean实例时,它会使用equals()方法来比较各自的主键是否相等。
*/
public class AccountPK implements Serializable {
public String accountID;
public AccountPK(String id){
this.accountID = id;
}
public AccountPK(){}
public String toString(){
return accountID;
}
public int hashCode(){
return accountID.hashCode();
}
public boolean equals(Object account){
if(!(account instanceof AccountPK))
return false;
return ((AccountPK)account).accountID.equals(accountID);
}
}
package com.testproject.ejb.entity;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.ejb.EJBException;
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;
import javax.ejb.RemoveException;
import javax.naming.Context;
import javax.naming.InitialContext;
public class AccountBean implements EntityBean {
protected EntityContext ctx;
//BMP持久化域
private String accountID;
private String ownerName;
private double balance;
//业务逻辑方法
/** *//**
* 将amt存入账户
*/
public void deposit(double amt){
System.out.println("deposit("+amt+")called");
balance += amt;
}
/** *//**
* 从银行账户去amount
*/
public void withdraw(double amt){
System.out.println("withdraw("+amt+")called");
if(amt>balance){
}
balance -= amt;
}
public String getAccountID() {
return accountID;
}
public void setAccountID(String accountID) {
this.accountID = accountID;
}
public String getOwnerName() {
return ownerName;
}
public void setOwnerName(String ownerName) {
this.ownerName = ownerName;
}
public double getBalance() {
return balance;
}
/** *//**
* Home业务方法独立于任何账号,它返回银行账号的总和
*/
public double ejbHomeGetTotalBanValue()throws Exception{
PreparedStatement pstmt = null;
Connection conn = null;
double total = 0;
try{
System.out.println("ejbHomeGetTotalBankValue()");
/**//*获得数据库连接*/
conn = getConnection();
/**//*合计*/
pstmt = conn.prepareStatement("select sum(balance) as total form accounts");
ResultSet rs = pstmt.executeQuery();
if(rs.next()){
total = rs.getDouble("total");
}
}catch(Exception e){
e.printStackTrace();
throw e;
}
finally{
/**//*释放资源*/
try{if(pstmt!=null)pstmt.close();}
catch(Exception e){}
try{if(conn!=null)conn.close();}
catch(Exception e){}
}
return total;
}
/** *//**
* 从连接池获得JDBC连接
*/
public Connection getConnection()throws Exception{
try{
Context ctx = new InitialContext();
javax.sql.DataSource ds = (javax.sql.DataSource)ctx.lookup("java:comp/env/jdbc/ejbPool");
return ds.getConnection();
}catch(Exception e){
e.printStackTrace();
throw e;
}
}
//回调方法先不写了,实在太多
public void ejbActivate() throws EJBException, RemoteException {
}
public void ejbLoad() throws EJBException, RemoteException {
}
public void ejbPassivate() throws EJBException, RemoteException {
}
public void ejbRemove() throws RemoveException, EJBException,
RemoteException {
}
public void ejbStore() throws EJBException, RemoteException {
}
public void setEntityContext(EntityContext arg0) throws EJBException,
RemoteException {
}
public void unsetEntityContext() throws EJBException, RemoteException {
}
}
posted on 2009-11-21 12:32
王永庆 阅读(208)
评论(0) 编辑 收藏 所属分类:
EJB学习笔记