EJB(Enterprise JavaBeans)入门(9) Bean-Managed Persistence(BMP) 本章讲述了Bean-Managed 和 Container-Managed persistence 的区别 、如何实现 Bean-managed persistence 的实体 Bean本章讲述内容 - 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("<?xml version=\"1.0\" ?>\n"); out.print("<client id=\""); out.print(getId()); out.print("\">\n\t<first>"); out.print(getFirstName()); out.print("</first>\n\t<last>"); out.print(getLastName()); out.print("</last>\n\t<phone>"); if (getPhoneNumber() != null) out.print(getPhoneNumber()); out.println("</phone>\n</client>"); out.close(); } catch (IOException e) { e.printStackTrace(); throw new RemoteException("An IO error occurred", e); } } | | <?xml version="1.0" ?> <client id="999999"> <first>Kenneth</first> <last>Beaton</last> <phone>555-9999</phone> </client> | · 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<files.length;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
(全文完)
|