ITPub博客

首页 > Linux操作系统 > Linux操作系统 > [转载]使用 Access Bean 将 SQL EJB 包装器实现成模型助手

[转载]使用 Access Bean 将 SQL EJB 包装器实现成模型助手

原创 Linux操作系统 作者:dinner1007 时间:2019-04-04 14:15:07 0 删除 编辑

使用 Access Bean 将 SQL EJB 包装器实现成模型助手


本文提供了前一篇文章'Using a Generic SQL Entity EJB Wrapper to Simplify EJB development'中所描述的包装器的一个样本实现。本文还描述了性能问题。

简介

在介绍性文章 使用通用 SQL EJB 包装器简化 EJB 开发 中提出了一种用于简化自底向上(bottom-up)EJB 开发的编程技术。在接下来的这篇文章里,我们提供了该包装器的一个样本实现,并且描述了这种包装器如何在现有的基础设施上工作。

IBM 架构师建议程序员使用模型助手(model helper)来简化实体 EJB 的使用[ 1]。模型助手可以让您像使用普通 Java Bean 一样使用实体 Bean。WebSphere® Studio 通过提供一个Access Bean 基础设施来支持这种模型助手的实现。Access Bean 由一个 EJB 工厂和一个数据类组成。其中,工厂负责管理 EJB 的生命周期,而数据类提供了数据存储和可缓存企业 Bean 属性的访问方法。通过管理 EJB 接口可以节省很多工作。

在这篇文章中,我们描述了使用 Access Bean 技术来实现 SQL EJB 包装器的例子。我们还将讨论与底层数据库管理系统(DBMS)相关的性能问题。




回页首


安装例子

安装必需的软件

  1. 安装 DB2 UDB v8.1.2
  2. 安装 Websphere Studio Enterprise Edition v5。

创建样本数据库

创建样本数据库的步骤:

  1. 下载 TradeDB.bat.
  2. 打开 DB2 Command Window。
  3. 在打开的 DB2 Command Window 中运行 TradeDb.bat

导入应用程序

把应用程序导入到 Enterprise Developer configuration of WebSphere Studio 中,需要完成下面几步:

  1. 下载 EjbWraper.ear
  2. 启动 WebSphere Studio。
  3. 在 WebSphere Studio 中,点击 File->Import 打开 Import 窗口。
  4. 在 Import 窗口中,选择前面下载的 EAR 文件,然后点击 Next
  5. 在接下来的 Import 窗口中,在 Ear File 字段中选择 EjbWraper.ear , 并且在 Project Name 字段中键入 EjbWraper , 然后点击 Finish。
  6. \runtimes\ee_v5\lib 目录导入 Query.ear

设置 classpath

现在加入所需要的包到 classpath 中:

  1. 打开 J2EE 透视图。
  2. 鼠标右键点击 TradeEJB 项目并且选择 Properties。
  3. 在 Properties for TradeEJB 窗口中,选择 Java Build Path 面板上的 Libaries标签。
  4. 选择 Add External JARs 并从目录 \runtimes\ee_v5\lib 加入 query.jar qryclient.jar

创建测试服务器

创建测试样本应用程序的服务器:

  1. 打开 Server 透视图。
  2. 在 Server Configurations 面板中,鼠标右键点击 Servers并且选择 New->Server and Server Configurations
  3. 在 Create a New Server and Server Configuration 窗口中( 图 1),在 Server name 字段中键入 EjbWrapTestServer 并且选择 EE Test Environment,然后点击 Finish
    图 1.创建测试服务器
    Figure 1. Creating a test server
  4. 在 Server Configuration 面板中,鼠标右键点击 Servers->EjbWrapTestServer,并选择 Add->EjbWrapper,对 Query.ear 项目也做同样的操作。
  5. 在 Server Configuration 面板中,鼠标右键点击 Servers->EjbWrapTestServer 并选择 Open选项打开服务器配置。
  6. 选择 Security标签并为 Trade 用户加入 Trade JAAS Authentication Entries图 2).
    图 2. 加入认证入口
    Figure 2. Adding authentication entries
  7. 选择 Data Source 标签,加入一个 JNDI 名为 jdbc/Trade 的、V5 类型的数据源和一个名为 TradeDB 的数据库。为 EjbWraper 设置组件管理的认证别名和容器管理的认证别名( 图 34
    图 3. 加入数据源
    Figure 3. Adding a datasource

    图 4. 加入数据源(续)
    Figure 4. Adding a datasource, con't

测试代码

运行 Tradedb 会话 bean 以测试该代码,该会话 bean 包含了针对测试服务器上的包装器代码的测试函数:

  1. 打开 Server 透视图。
  2. 在 Server 视图中,确定 Server State 是“Server is synchronized”。鼠标右键点击 EjbWraperTestServer 并选择 Start。这样就启动了测试服务器。
  3. 打开 J2EE 透视图。
  4. 在 J2EE Hierarchy 视图中,鼠标右键点击 Tradedb 会话 bean, 并选择 Run on Server。这将启动 Universal Test Client
    图 5)。
    图 5. 通用测试客户端
    Figure 5. Universal Test Client
  5. 在 References 面板中,展开 Tradedb->TradedbHome 选项,并且用 create() 方法创建一个对 Tradedb 的引用。
  6. 调用样本代码中任何测试函数。
    图 6. 在测试客户端调用测试函数
    Figure 6. Invoking a test function from the test client

这时,样本应用程序就已经在运行了。让我们来看看源代码。




回页首


模型类

模型类是这里的 EJB 助手类。 清单 1显示了 TradeaccountbeanModel 类的成员及方法。


清单 1. 模型类
public class TradeaccountbeanModel
{
private Vector beanInterface = new Vector();
public Vector Select(String userid, Double balance, Integer transactions)
throws javax.ejb.FinderException
{ /*?*/ }
public void Insert(String userid, Double balance, Integer transactions)
throws javax.ejb.CreateException
{ /*?*/ }

public void Delete() throws javax.ejb.RemoveException
{ /*?*/ }
public void Update(String userid, Double balance, Integer transactions)
{ /*?*/ }
}

TradeaccountbeanModel类由 beanInterface 类成员以及 Select()、Insert()、Delete() 和 Update() 方法组成。

Select()、Insert()、Delete() 和 Update() 方法在 介绍性文章 中有描述。您可以任意地加入自定义的方法到该模型助手中。

beanInterface 类成员是作为查询结果的 bean 引用的一个集合。这样做是为了将 bean 引用缓存起来,以便随后对其进行操作。

我们将会在下面的部分介绍每个 SQL 方法的实现。




回页首


Insert 方法

对 bean 创建方法的调用将导致向底层数据库进行一次插入操作。参见 清单 2以获得对插入操作的一个典型实现。


清单 2. 插入的一个典型实现
public void Insert(String userid, Double balance, Integer transactions)
throws javax.ejb.CreateException
{
TradeaccountbeanFactory factory = new TradeaccountbeanFactory();
try
{
Tradeaccountbean bean = factory.create(userid);
bean.setUserid(userid);
bean.setTransactions(transactions);
beanInterface.add( bean );
}
catch (java.rmi.RemoteException re)
{
}
}

EJB 工厂类是一个访问 Bean,可用于简化企业 bean 实例的创建和发现。在我们上面的例子中, TradeaccountbeanFactory 的作用是用相应的主键创建一个 Tradeaccountbean 实体 bean 的实例。实体 bean 中默认的 setter 方法用来初始化容器管理的持久性(CMP)的两个字段: useridtransactions。但是这种实现不仅导致了一次插入操作,而且还引入了两次额外的更新操作。

参见 清单 3以查看对插入操作更高效的实现例子。


清单 3. 更高效的插入实现
public void Insert(String userid, Double balance, Integer transactions)
throws javax.ejb.CreateException
{
TradeaccountbeanFactory factory = new TradeaccountbeanFactory();
try
{
beanInterface.add(factory.create(userid, balance, transactions));
System.out.println("Insert");
}
catch (java.rmi.RemoteException re)
{
throw new EJBException(re);
}
}

在这个实现中,我们使用了 EJB 工厂类的 create 方法,并把所有 CMP 字段一次性全部传给该方法。这样就会只产生一次插入操作,从而满足了我们的要求。

为了能够使用上面的 create 方法,必须在 home 类中加入与所有 CMP 字段对应的特征标(signature)。 参见 清单 4 中给出的例子。


清单 4. 将方法 ejbCreate() 加入到 TradeaccountbeanBean.java 中
public sample.TradeaccountbeanKey ejbCreate(
java.lang.String userid,
java.lang.Double balance,
java.lang.Integer transactions)
throws javax.ejb.CreateException
{
setUserid(userid);
setBalance(balance);
setTransactions(transactions);
return null;
}

然后必须将 清单 5中列出的方法加入到 home 类中。


清单 5. 把 create() 加入到 TradeaccountbeanHome.java 中
public sample.Tradeaccountbean create(
java.lang.String userid,
Double balance,
Integer transactions)
throws javax.ejb.CreateException, java.rmi.RemoteException;




回页首


Select 方法

Select() 方法是编程技术中所描述的选择过滤模板。它提供了一个经常使用的 SELECT-WHERE-AND 访问。参见 清单 6 中对选择方法的实现。

清单 6. 传统的选择实现
public Vector Select(String userid, Double balance, Integer transactions)
throws javax.ejb.FinderException
{
Enumeration bean = null;
Vector queryResult = new Vector();
try
{
bean = findByWhereClause(userid, balance, transactions);
while ( e.hasMoreElements() )
{
beanInterface.add(bean);
queryResult.add(bean.getTradeaccountbeanData());
}
}
catch (java.rmi.RemoteException re)
{
}
return queryResult;
}

一种实现选择性过滤的方法是根据客户提交的参数动态地产生一个 JDBC 查询。这样产生的结果集将会是想要的数据。要获得对 bean 的引用,我们可以调用每个 EJB 默认的 findByPrimaryKey() 方法。如果您看了上面提供的源代码,那么这正是 findByPrimaryKey() 方法所做的。通过这种方式,任何一次对 Select() 方法的调用都会导致 N+1 次对数据库的选择操作,这里 N 是结果集的大小。

对我们不知道查询搜索标准的应用程序来说,只有到了应用程序运行时,我们才可能希望使用 IBM 动态访问服务(DQS)[ 1]。参见 清单 7 以了解通过利用 DQS 技术的优点而得出的一个更高效的选择实现。

清单 7. 一个基于 DQS 的选择实现
public Vector Select(String userid, Double balance, Integer transactions)
throws javax.ejb.FinderException
{
String query = "SELECT OBJECT(a) FROM Tradeaccountbean a ";
Vector queryResult = new Vector();

//Generate the EJBQL query
try
{
int count = 0;
Object[] parms = new Object[3];

if (userid != null || balance != null || transactions != null)
{
int markPos = 0;

query = query + " WHERE ";

if (userid != null)
{
query += "a.userid = ?1";
parms[count] = new String (userid);
count++;
}

if (balance != null)
{
if (count == 0)
{
query += "a.balance = ?1";
}
else
{
markPos = count + 1;
query += " AND a.balance = ?" + markPos;
}

parms[count] = balance;
count++;
}

if (transactions != null)
{
if (count == 0)
{
query += "a.transactions = ?1";
}
else
{
markPos = count + 1;
query += " AND a.transactions = ?" + markPos;
}

parms[count] = transactions;
count++;
}
}

System.out.println("Query: " + query);

Query qb = QueryBeanFactory.getQuery();
QueryIterator it;

Object[] newParms;

if (count == 0)
newParms = null;
else
{
newParms = new Object[count];
for (int i = 0; i < count; i++)
newParms[i] = parms[i];
}

//Query Database
it = qb.executeQuery(query, newParms, null, 0, 1000);

qb.remove();

//Get the query result
while (it.hasNext())
{
IQueryTuple t = (IQueryTuple) it.next();
Tradeaccountbean accountbean = (Tradeaccountbean)t.getObject(1);
beanInterface.add(accountbean);
queryResult.add(accountbean.getTradeAccountBeanData());
}

return queryResult;

}
catch (Exception e)
{
e.printStackTrace();
throw new EJBException (e);
}
}

动态访问 API 实际上是一个查询型(Query)无状态会话 bean。在执行一个查询以前,我们必须获得对查询会话 bean 的一个引用,或者通过 JNDI 获得,或者通过工厂类获得。在上面的代码中,该查询会话 bean 是通过 QueryBeanFactory工厂类获得的。

动态查询用一个 String传入,而其它输入参数以任何 java.lang.Object 值的数组的形式传入。所以,查询和参数可以根据 Select() 方法客户机提供的搜索标准动态地组合。

调用 QueryIterator的 next() 方法会返回一个 IQueryTuple 实例,该实例包含了实际的数据和对象引用。为了我们的目的,我们把对象的引用保存起来以便以后使用它们,并且返回数据类作为查询的结果。

这个 Select() 模板的实现将被翻译成对底层数据库的惟一的选择语句。很明显,DQS 提供了非常灵活的实现 Select() 过滤的机制。如果想了解更多关于 DQS 的信息,参见 WebSphere 信息中心[ 4]。




回页首


Delete 方法

下面是对删除方法的一个实现。


清单 8. 删除的一个实现
public void Delete() throws javax.ejb.RemoveException
{
System.out.println("Delete");
try
{
for (int i = 0; i < beanInterface.size(); i++)
((Tradeaccountbean) beanInterface.get(i)).remove();
}
catch (java.rmi.RemoteException re)
{
throw new EJBException(re);
}
}

通过调用 bean 中的 remove() 方法,可以逐个地删除上一次查询所得的所有 bean。




回页首


Update 方法

在 EJB 编程模型中,更新对程序员来说是比较透明的。任何对 CMP 字段的更改都将导致对数据库进行更新操作。参见 清单 9 以查看一个典型的更新实现。


清单 9. 一个典型的更新实现
public void Update(String userid, Double balance, Integer transaction)
{
Tradeaccountbean b = null;
try
{
for (int i = 0; i < beanInterface.size(); i++)
{
b.setBalance(balance);
b.setTransactions(transaction);
}
}
catch (java.rmi.RemoteException re)
{
}
}

我们所要做的就是调用 WebSphere Studio 提供的默认 setter 方法。注意对 setter 方法的每次调用是一次独立的更新。在上面的例子中,有两条更新语句,一条是更新 balance,另一条是更新 transaction

参见 清单 10以查看一个更高效的更新实现。


清单 10. 一个更高效的更新实现
public void Update(String userid, Double balance, Integer transaction)
{
Tradeaccountbean b = null;
TradeaccountbeanData d = null;
try
{
for (int i = 0; i < beanInterface.size(); i++)
{
// Get data class of each bean
b = ((Tradeaccountbean) beanInterface.get(i));
d = b.getTradeaccountbeanData();
// Update each data class
d.setBalance(balance);
d.setTransactions(transaction);
b.syncTradeaccountbeanData(d);
}
}
catch (java.rmi.RemoteException re)
{
throw new EJBException(re);
}
}

数据类访问 Bean 提供了数据存储和针对可缓存的企业 bean 属性的访问方法。sync XXXData() 方法会将您对数据类的任何更改写回到该企业 bean 中。在我们的例子中,通过 TradeaccountbeanData 数据类的 setter 方法来更新 balancetransaction。然后调用 syncTradeaccountbeanData() 方法来同步这种变化。这里只触发了一次更新语句。




回页首


结束语

本文描述了一种 SQL EJB 包装器的样本实现。该 SQL 包装器支持模型助手的概念。而且这种包装器可以很好地和 WebSphere Studio 中的 Access Bean 一起工作。实现这种包装器的一个重要方面是,确保包装器使用有利于 EJB 性能的最佳实践。在这篇文章中,我们还介绍了数据库访问方面的最佳实践。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/374079/viewspace-130620/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2018-08-23

  • 博文量
    671
  • 访问量
    460905