使用动态查询服务

在开发流程中,有时您可能想使用动态查询服务,而不想使用常规 Enterprise JavaBean (EJB) 查询服务(可称为部署查询)。例如,在测试期间,可以在应用程序运行时使用动态查询服务,因此不必重新部署应用程序。

关于此任务

下列是使用动态查询服务而不使用常规 EJB 查询服务的常见原因:
  • 您需要通过程序在应用程序运行时(而不是在部署时)对查询进行定义。
  • 您必须从一个查询返回多个 CMP 或 CMR 字段。(部署查询只允许在 SELECT 子句中指定一个元素。)有关更多信息,请参阅主题“示例:EJB 查询”。
  • 您要在查询中返回一个计算表达式。
  • 您要在查询语句中使用值对象方法或 Bean 方法。有关更多信息,请参阅主题“路径表达式”。
  • 您要在开发过程中对 EJB 查询进行交互测试,但不希望每次更新 finder 或 select 查询时重复部署应用程序。

动态查询 API 是一个无状态会话 Bean;它的使用方法类似于任何其他 J2EE EJB 应用程序 Bean。它包含在 API 包的 com.ibm.websphere.ejbquery 中。

动态查询 Bean 具有一个远程接口和一个本地接口。如果您希望从查询返回远程 EJB 引用或是查询语句包含远程方法,您必须使用查询远程接口:

remote interface = com.ibm.websphere.ejbquery.Query
remote home interface = com.ibm.websphere.ejbquery.QueryHome

如果希望从查询返回本地 EJB 引用或是查询语句包含本地方法,您必须使用查询本地接口:

local interface = com.ibm.websphere.ejbquery.QueryLocal
local home interface = com.ibm.websphere.ejbquery.QueryLocalHome

因为本地接口使用的应用程序服务器内存较少,所以它的整体 EJB 性能比远程接口更出色。

过程

  1. 验证 query.ear 应用程序文件是否已安装到将运行应用程序的应用程序服务器中(如果该服务器不同于安装产品过程中创建的缺省应用程序服务器)。
    query.ear 文件位于 app_server_root 目录中,其中 <WAS_HOME> 是 WebSphere Application Server 的位置。产品安装程序使用 JNDI 名称
    com/ibm/websphere/ejbquery/Query
    query.ear 文件安装在缺省应用程序服务器中(您或系统管理员可以更改这个名称)。
  2. 为远程和本地动态查询接口中的 executeQuery()、prepareQuery() 和 executePlan() 方法设置权限以控制对敏感数据的访问。(仅当您的应用程序需要安全性时才需要这个步骤。)

    因为您无法控制动态 EJB 查询中可以使用哪些 ASN 名称、CMP 字段或 CMR 字段,所以您或系统管理员必须对这些方法的使用作出限制。例如,如果允许用户运行 executeQuery 方法,他/她就可以运行任何有效的动态查询。在生产环境中,您肯定希望限制对远程查询接口方法的访问。

  3. 将动态查询编写为您的应用程序客户机代码的一部分。您可以参考示例主题“远程接口动态查询示例”和“本地接口动态查询示例”作为查询模型;它们说明了要使用哪些 import 语句。
  4. 如果要查询的 CMP 位于不同的模块中,您应该:
    1. 对 query.ear 执行远程查找
    2. 将 query.ear 文件映射至安装查询的 CMP Bean 的服务器。
  5. 使用类路径中的文件 qryclient.jar 编译并运行您的客户机程序。

示例

将远程接口用于动态查询。

使用远程接口运行动态 Enterprise JavaBeans (EJB) 查询时,您是对 Query 接口调用 executeQuery 方法。executeQuery 方法对该接口具有一个值为 REQUIRED 的事务属性;因此,您无需显式建立一个事务上下文即可运行查询。

使用远程接口运行动态 Enterprise JavaBeans (EJB) 查询时,您是对 Query 接口调用 executeQuery 方法。executeQuery 方法对该接口具有一个值为 REQUIRED 的事务属性;因此,您无需显式建立一个事务上下文即可运行查询。

用以下导入语句作为开头:

import com.ibm.websphere.ejbquery.QueryHome;
import com.ibm.websphere.ejbquery.Query;
import com.ibm.websphere.ejbquery.QueryIterator;
import com.ibm.websphere.ejbquery.IQueryTuple;
import com.ibm.websphere.ejbquery.QueryException;

接着,以字符串形式编写您的查询语句,如以下示例所示(该示例检索未付足工资员工的姓名和 EJB 引用):

String query = 
"select e.name as name , object(e) as emp from EmpBean e where e.salary < 50000"; 

通过从 QueryHome 类获取一个引用来创建 Query 对象。(这个类定义了 executeQuery 方法。)请注意,为简洁起见,以下示例对 Query 对象使用动态查询 JNDI 名称:

InitialContext ic =  new InitialContext(); 

Object obj =  ic.lookup("com/ibm/websphere/ejbquery/Query");

QueryHome  qh = 
 ( QueryHome) javax.rmi.PortableRemoteObject.narrow( obj, QueryHome.class );
Query qb = qh.create();

随后,您必须为查询结果集指定一个最大大小,它在 QueryIterator 对象(随 Class QueryIterator 附带)中定义。随后,您必须为查询结果集指定一个最大大小,它在 QueryIterator 对象(随 QueryIterator API 包附带)中定义。该示例将结果集的最大大小设置为 99:

QueryIterator it = qb.executeQuery(query, null, null ,0, 99 );
迭代器包含一组 IQueryTuple 对象,它们是返回集合值的记录。根据示例查询语句中的条件,该方案中的每个元组包含一个 name 值和一个 object(e) 值。要显示该查询结果的内容,请使用以下代码:
while (it.hasNext() ) { 
	IQueryTuple tuple = (IQueryTuple) it.next();
	System.out.print( it.getFieldName(1) );
	String s = (String) tuple.getObject(1);
	System.out.println( s);
	System.out.println( it.getFieldName(2) );
	Emp e = ( Emp) javax.rmi.PortableRemoteObject.narrow( tuple.getObject(2), Emp.class );
	System.out.println( e.getPrimaryKey().toString());
}
程序的输出可能类似于以下内容:
name Bob 
emp 1001
name Dave
emp 298003
...
最后,捕获并处理任何异常。运行时处理错误或查询语句中的语法错误可能导致出现异常。以下示例捕获并处理了这些异常:
} catch (QueryException qe) {
    System.out.println("Query Exception "+ qe.getMessage() );
}

处理远程接口查询的大型结果集合

如果您计划使查询返回一个大型集合,那么可以选择对它进行编程,以返回多个更容易管理、更小的结果集合。在远程 executeQuery 方法中使用 skipRow 和 maxRow 参数以分块检索答案。例如:

int skipRow=0;
int maxRow=100;
QueryIterator it = null;
do {
	it = qb.executeQuery(query, null, null ,skipRow, maxRow );
	while (it.hasNext() ) { 
	// display result 
	skipRow = skipRow + maxRow;
}
} while ( ! it.isComplete() ) ;
将本地接口用于动态查询。

使用本地接口运行动态 Enterprise JavaBeans (EJB) 查询时,您是在 QueryLocal 接口上调用 executeQuery 方法。此接口不会为该方法发起一个事务;因此,您必须显式建立一个事务上下文供查询运行。

注: 要建立一个事务上下文,以下示例调用了 begin() 和 commit() 方法。使用这些方法的另一个替代方法是,您只要将查询代码嵌入事务上下文中运行的 EJB 方法即可。

查询代码用以下导入语句作为开头:

import com.ibm.websphere.ejbquery.QueryLocalHome;
import com.ibm.websphere.ejbquery.QueryLocal;
import com.ibm.websphere.ejbquery.QueryLocalIterator;
import com.ibm.websphere.ejbquery.IQueryTuple;
import com.ibm.websphere.ejbquery.QueryException;

接着,以字符串形式编写您的查询语句,如以下示例所示(该示例检索未付足工资员工的姓名和 EJB 引用):

String query = 
"select e.name, object(e) from EmpBean e where e.salary < 50000 ";

通过从 QueryLocalHome 类获取一个引用创建一个 QueryLocal 对象。(这个类定义了 executeQuery 方法。)请注意,在以下示例中,ejb/query 用作一个指向动态查询 JNDI 名称(com/ibm/websphere/ejbquery/Query)的本地 EJB 引用:

InitialContext ic =  new InitialContext(); 
   QueryLocalHome  qh =  ( LocalQueryHome) ic.lookup( "java:comp/env/ejb/query" );
QueryLocal qb = qh.create();

代码的最后一部分发起一个事务,调用 executeQuery 方法并显示查询结果。将对 QueryLocalIterator 类进行实例化,因为它定义了查询结果集。这个类包含在 Class QueryIterator API 包中。请记住,迭代器将在事务结束时失效;您必须在 executeQuery 调用的同一事务作用域中使用迭代器。

userTransaction.begin();
QueryLocalIterator it = qb.executeQuery(query, null, null);
while (it.hasNext() ) { 
	IQueryTuple tuple = (IQueryTuple) it.next();
	System.out.print( it.getFieldName(1) );
	String s = (String) tuple.getObject(1);
	System.out.println( s);
	System.out.println( it.getFieldName(2) );
	EmpLocal e = ( EmpLocal ) tuple.getObject(2);
	System.out.println( e.getPrimaryKey().toString());
}
userTransaction.commit();

在多数情况下,QueryLocalIterator 对象是需求驱动的。即,它导致数据呈增量返回:对于每个数据库记录检索,必须在迭代器上调用 next() 方法。(某些情况下,迭代器也可以不是需求驱动的。有关更多信息,请查阅动态查询性能注意事项主题中的“本地查询接口”子部分。)

因为应用程序服务器内存中的完整查询结果集将呈增量具体化,所以您可以轻松控制它的大小。例如,在测试运行中,您可以决定只需返回几组查询结果。在这种情况下,您应该在 QueryLocalIterator 对象上使用 close() 方法的一个调用来结束查询循环。这样做可以释放迭代器使用的 SQL 资源。否则只有内存中累积了完整的结果集或事务结束时,才会释放这些资源。


指示主题类型的图标 任务主题



时间戳记图标 最近一次更新时间: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=tque_dynamic
文件名:tque_dynamic.html