EJB 入门
Bean-Managed Persistence(BMP)
本章讲述内容
- Bean-Managed 和 Container-Managed persistence 的区别
- 如何实现 Bean-managed persistence 的实体 Bean
Bean-Managed Persistence
- 容器管理 Bean
的生命周期--何时创建、载入、存储和删除
- 开发人员处理其机制--如何创建、载入、存储和删除
-
BMP = [业务逻辑] + [存储逻辑]
为何使用 BMP?
- 为了存储 CMP 现阶段所不能处理的复杂的 Bean
- 包含如下数据的实体 Bean:
- 内嵌 Java 对象
- 对象的集合
- 对其它 Bean 的引用
- ...
- CMP 所不支持的数据源
注意!
BMP
将您紧紧地绑定到某个特定的存储机制上--可能将您限制于一个特定的平台!
生命周期
创建 Bean
- 在 Home 接口的 Create 方法在 Bean 实例中有对应的 ejbCreate
方法--ejbCreate 方法返回一个主键对象
- 可以有任意数目的 create 方法
public ClientKey ejbCreate(int id, String first, String last) throws CreateException, RemoteException { if (new File("client." + id).exists()) throw new CreateException(); setFirstName(first); setLastName(last); setPhoneNumber(null); return new ClientKey(id); } |
|
存储
ejbStore() 方法完成工作--entityContext 包含主键
public void ejbStore() throws RemoteException { try { ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("client." + getId())); out.writeObject(getFirstName()); out.writeObject(getLastName()); out.writeObject(getPhoneNumber()); out.close(); } catch (IOException e) { throw new RemoteException("An IO error occurred", e); } } |
|
private int getId() { return ((ClientKey)getEntityContext().getPrimaryKey()).id; } |
|
载入
- 在进行载入前,entityContext 将被设置--entityContext
包含主键
- 使用主键的值来查找和载入 Bean
public void ejbLoad() throws RemoteException { try { ObjectInputStream in = new ObjectInputStream(new FileInputStream("client." + getId())); setFirstName((String)in.readObject()); setLastName((String)in.readObject()); setPhoneNumber((String)in.readObject()); in.close(); } catch (ClassNotFoundException e) { // Shouldn't happen -- We're dealing with Strings here. } catch (IOException e) { throw new RemoteException("An IO error occurred", e); } } |
|
删除 ejbRemove() 方法用来完成删除工作
public void ejbRemove() throws RemoteException, RemoveException { File file = new File("client." + getId()); if (!file.exists()) throw new RemoveException(); file.delete(); } |
|
XML 示例
public void ejbStore() throws RemoteException { try { PrintWriter out = new PrintWriter(new FileWriter("client." + getId())); out.println("
"); out.print(" out.print(getId()); out.print("">
"); out.print(getFirstName()); out.print("
"); out.print(getLastName()); out.print("
"); if (getPhoneNumber() != null) out.print(getPhoneNumber()); out.println("
"); out.close(); } catch (IOException e) { e.printStackTrace(); throw new RemoteException("An IO error occurred", e); } } |
|
|
Finder 方法
- 对每个在 Home 接口中声明的 find 方法必需有一个对应的 ejbFind
方法
- 单个查找--返回的是找到对象的主键
- 多个查找--返回的是匹配对象的主键的枚举
- 容器将载入 Bean--一个 Bean 从池中取出,赋以主键(通过
entityContext)然后被调用载入方法
单个查找
public ClientKey ejbFindByPrimaryKey(ClientKey key) throws RemoteException, FinderException { if (!new File("client." + key.id).exists()) throw new FinderException(); return key; } |
|
public ClientKey ejbFindById(int id) throws RemoteException, FinderException { if (!new File("client." + id).exists()) throw new FinderException(); return new ClientKey(id); } |
|
多个查找
public Enumeration ejbFindAll() throws RemoteException, FinderException { String[] files = new File(".").list(new FilenameFilter() { public boolean accept(File directory, String name) { return name.startsWith("client."); } }); Vector keys = new Vector(); for (int index=0;index String name = files[index]; int id=Integer.parseInt(name.substring(name.indexOf('.') + 1)); keys.addElement(new ClientKey(id)); } return keys.elements(); } |
|
多个查找 (JDBC 版本)
public Enumeration ejbFindAll() throws RemoteException, FinderException { Vector keys = new Vector(); Connection connection = null; PreparedStatement statement = null; try { connection = getDataSource().getConnection(); statement = connection.prepareStatement("Select ID from CLIENT"); ResultSet results = statement.executeQuery(); while (results.next()) { int id = results.getInt(1); keys.addElement(new ClientKey(id)); } results.close(); } catch (SQLException e) { } finally { try {statement.close();} catch (SQLException e) { } try {connection.close();} catch (SQLException e) {} } return keys.elements(); } |
|
JDBC 载入示例
public void ejbLoad() throws RemoteException { Connection connection = null; PreparedStatement statement = null; try { connection = getDataSource().getConnection(); statement = connection .prepareStatement("Select FIRST, LAST, PHONE from CLIENT where ID=?"); statement.setInt(1, getId()); ResultSet results = statement.executeQuery(); if (results.next()) { setFirstName(results.getString(1)); setLastName(results.getString(2)); setPhoneNumber(results.getString(3)); } else { throw new RemoteException("The row cannot be found!"); } results.close(); } catch (SQLException e) { ... } |
|
查找的过程
- 有一个 Bean 实例被用来查找出其它实例--Bean
必需被从池中取出来进行查找工作
- Bean 实例必需自己将自己载入--可能开销会很大
- 使用 JDBC:
- 一个调用用来取出所有您所关心的 Bean 的 id
- 对每个 id 又是一个调用来取出一行数据
- 总共需要 n+1 个对数据库的访问来载入 n 个 Bean!
本章讲述内容
- Bean-Managed Persistence 允许 Bean
开发人员指定如何实现数据的存储
- ejbLoad, ejbStore 和 ejbRemove 方法必需先从 entityContext
中获得主键
- BMP create 方法必需返回主键
- 对应每个在 Home 接口中的 find* 方法必需有一个对应的 ejbFind*
方法--开发人员必需至少提供 ejbFindByPrimaryKey