摘要:构建访问联邦数据的 Web 组件
级别: 中级
C.M. Saracco
DBMS 和 Web 应用程序服务器集成部门, IBM 硅谷实验室
2002 年 9 月
联邦 DBMS 在应付完全不同的数据方面为 Web 设计师提供帮助。在三分之二的设计师之中,作者 C. M. Saracco 开发出了许多方法,用这些方法构建的基于 Java 的组件——比如会话 Enterprise JavaBeans(EJB)和 Web 服务—— 能够使用联邦数据。
简介
Java™ 程序员在构建用于支持 Web 应用程序的组件时通常不得不面对麻烦的数据访问问题。虽然单单操作远程关系数据库管理系统(DBMS)中的数据是个相当简单的任务,但集成多个数据源的数据却不那么容易。通常,这种数据驻留在不同的服务器中,以不同的数据格式存储并且只能通过不同的应用程序编程接口(API)或结构化查询语言(SQL)方言来访问。这些问题增加了手头任务的复杂性,延长了开发周期,增加了长期的维护成本。
然而, 存取数据只是问题的一部分。对完全不同的数据进行组合、过滤、排序和合并是件艰难和费时费力的任务。简化操作会导致滥用计算资源、用户的响应时间变长和数据服务器的性能变差。由于这些原因,许多 Web 组件程序员宁愿把数据访问和集成问题委托其他人去完成。而且这些“其他人”实际上可能是其它 东西——一个联邦数据服务器。
联邦 DBMS 技术,在 20 世纪 90 年代以商业化形式出现,给程序员提供了完全不同的数据在单一地点的映象。程序员连接到一个由联邦 DBMS 维护的虚拟数据库,并使用它的 API 去访问可能由其它地方的多种数据源所管理或生成的数据。联邦 DBMS 在幕后工作,使得对于这种完全不同的数据的访问透明且有效。这些工作包括自动数据变换、API 转换、功能补偿和数据访问操作的优化。
在我们早先的文章 “处理 Web 应用程序中完全不同的数据”里,我们给出了技术概述并提供了一个 IBM® 的 WebSphere® 和 DB2® 联邦技术样本体系结构。在本文中,我们将探究一些新方法,在这些方法中可以构建基于 Java 的组件 - 比如会话 Enterprise JavaBeans™(EJB)和 Web 服务 - 来使用联邦数据。在下一篇文章中,我们将看到怎样构建可以处理联邦数据的实体 EJB。
理解 Java 组件技术
构建在中间层 Web 应用程序服务器上运行的组件的 Java 程序员可以使用几种不同的技术实现其数据访问例程,这些技术包括 EJB、Web 服务、servlet 和 Java Server Pages™(JSP)。这些技术中的每一种都不同,但是都对 Java 开发人员提出了一些共同的编码需求。对关系数据(或由关系 DBMS 管理的联邦数据)进行访问意味着需要编写 JDBC 或 SQLJ 代码。JDBC 是目前最常用的。使用关系数据要求程序员建立到目标数据库的连接、发出 SQL 语句以及管理事务。我们将简短地讨论每个问题,特别关注当涉及联邦数据时将如何处理这些问题。但首先,让我们讨论会话 EJB 和 Web 服务的基础,同时我们将研究一下它们的编码示例。
会话 EJB(session EJB)
会话 EJB 是符合特定编程规范的 Java 2 企业版(J2EE)组件。这些 bean 可以使用持久数据,但不代表持久数据本身。也就是说,任何与会话 bean 相关的数据在调用者释放 bean 的资源后不会被持久存储 - 即不再继续存在。实体 bean 本质上是可持久的,我们将在下一篇文章中再作讨论。实体 EJB 代表外部存储的数据,典型的是存储在关系 DBMS 中的数据。
EJB 部署在由 Web 应用程序服务器(例如,WebSphere Application Server)管理的 容器中。这些容器提供生产服务,例如对安全性和事务管理的支持,因此程序员不需要在 bean 中显式地对这些功能编写代码。
会话 EJB 和实体 EJB 有稍许不同的编码需求,而且这些编码需求随所使用的 EJB 规范级别的不同而不同。本文着重讨论符合 EJB 1.1 规范的 bean,EJB 1.1 是 WebSphere Application Server 4.0所支持的级别。
在部署期间,每个会话 bean 都有多个代码模块,包括:
Home 接口:定义创建和除去 bean 实例的客户机方法。
Remote 接口:定义和 bean 相关的业务方法。
bean 类:包括了由 EJB 开发人员编码的业务逻辑方法以及容器所使用的 EJB 生命周期方法。EJB 客户机不直接访问该类的对象,而是使用容器生成的实现 Home 接口和 Remote 接口的类去间接利用该类的服务。
会话 bean 可以是 无状态(stateless)的也可以是 有状态(stateful)的。无状态会话 bean 在客户机调用期间不维持任何对话状态;客户机调用的每个方法被单独处理而且只使用与其输入参数相关的数据。有状态会话 bean 维护整个客户机会话期间的对话状态;一个方法可能会改变 bean 的一个属性的数据值,该数据值接下来也会影响所调用的后续方法的行为。本文中,我们重点讨论无状态会话 EJB 的使用。
程序员开发出一个 EJB 后,必须设置 部署描述符用于管理诸如事务支持、隔离级别及其它等特征。最后,必须在 EJB 服务器中打包和部署 bean。这个部署过程会产生额外的类,包括和 Home及 Remote接口相关的那些类。好的 Java 开发环境能加速 EJB 的开发、部署和测试;我们使用 WebSphere Studio Application Developer Integration Edition(WSADIE)4.1。
Web 服务
尽管万维网联盟(W3C)已经发布了许多有关 Web 服务各个方面的工作草案,但到我写这篇文章时,Web 服务还在迅猛发展。Web 服务不是 Java 规范的一部分,但是 Java 经常被作为开发 Web 服务的编程语言。
Web 服务是一个或多个业务功能的集合,这些功能可以由应用程序或其它 Web 服务以编程的方式通过因特网调用。从这点来讲,Web 服务有利于分布式计算,而且旨在提高互操作性。几种底层的技术在支持 Web 服务方面发挥了关键作用,这些技术包括 HTTP、可扩展标记语言(XML)、简单对象访问协议(SOAP)、Web 服务定义语言(WSDL)和统一描述、发现和集成协议(UDDI)。
Web 服务供应商发布他们的 Web 服务,这样客户机能够使用 SOAP 通过 HTTP 访问这些服务。这与使用远程方法调用(RMI)并通过因特网对象请求代理间协议(Internet Inter-Orb Protocol(IIOP))去访问 bean 的 EJB 客户机形成鲜明对比。
Web 服务处理来自 Web 客户机的请求 - 调用适当的业务功能并通常返回响应。Web 服务本身由存储在资源库(如 UDDI 注册中心)或 Web 服务供应商的服务器上的 WSDL 文档来描述。将 Web 服务描述存储在适当资源库中的这种方式为感兴趣的用户提供了发现其存在的可能性,从而可能会为服务供应商产生新的商机。
设置软件环境
在构建访问联邦数据的 Java 组件之前,必须配置您的 DBMS 客户机和服务器环境。在我们 较早的文章里,我们给出了完成配置一台与 DB2 V8 联邦 DBMS 进行相互操作的 DB2 V7.2 客户机的一系列步骤,而 DB2 V8 联邦 DBMS 本身已经进行了设置,可以对远程 Oracle、Sybase 和 Microsoft® SQL Server DBMS 上数据进行访问。在这我们不想重复所有的详细步骤;而是只对任务进行概述,以让您对任务中所涉及的内容有个大致了解。有关详细信息,请参阅前一篇文章或参考 DB2 产品手册。
首先,必须在您的客户机和服务器平台之间建立有效的基本连接(除非客户机和服务器软件是安装在同一台机器上)。我们使用 TCP/IP 进行通信,并向每个系统上的服务文件添加了几项,以指定我们使用的服务名和端口号。
建立连接后,我们要设置联邦 DBMS 服务器。这包括:
在 UNIX® 或 Windows® 平台上安装 DB2 V8 服务器实例
更新有关 SVCENAME 和 FEDERATED 的数据库管理器配置特性
创建一个 DB2 数据库(在我们的环境中是 rdjdb)以用于管理联邦访问
安装我们的目标数据源所要求的任何必备软件,并配置至这些数据源所在系统的网络访问
为我们希望访问的每个数据源创建封装器、服务器和用户映射对象
如果愿意的话,创建远程数据对象(例如远程 Oracle 表)的别名并基于这些别名创建视图
在本地测试服务器配置以确保一切工作正常后,我们就开始配置 Java 开发客户机。这包括:
安装 DB2 客户机软件。
指定有关我们的联邦数据库所在的远程节点的信息。
为远程联邦数据库指定一个逻辑数据库名称。在我们的环境中,我们使用了 djdb作为远程 rdjdb数据库的本地数据库名字。
为简化 Java 组件的开发和测试,我们还在客户机上安装了一个 Java 集成开发环境 - IBM 的 WSADIE 4.1。WSADIE 附带了 WebSphere Application Server的嵌入式副本,这使得我们能够在测试环境里快速方便地部署会话 EJB 和发布 Web 服务。设置 WSADIE 以使用联邦数据的过程包括:
把 db2java.zip 文件添加到 EJB 和 Web 项目的 Java 构建路径。
创建一个 WebSphere DataSource 对象以对应我们的联邦数据库。我们将 Java 命名和目录接口(JNDI)名称指定为 jdbc/Federated,并将 JDBC URL 指定为 jdbc:db2:djdb。我们还将用户标识和密码设置成了适当的值(分别是 user1和 passlword)。
建立数据库连接
当正确地配置了环境后,您就可以开发使用联邦数据的 Java 组件了。您所构建的任何组件在试图访问联邦数据库的数据前必须先建立与它的连接。构建会话 EJB、Web 服务、servlet 或 JSP 时,您要负责编写代码。当构建具有容器管理的持久性的实体 bean 时,您不必写这方面的代码 - EJB 容器会为您自动生成代码。我们将在今后的文章里讨论实体 EJB。
Java 程序员创建应用程序服务器组件时,在建立数据库连接方面有两个选择:他们可以使用不合用(umpool)或合用(pool)的连接。不合用连接基于 JDBC 1.0 规范,是这两种技术中较老的一种。不合用连接对于生产组件来说都是最不理想的,因为每一个组件都要带来创建新数据库连接和释放连接的开销。合用连接使用 JDBC 2.0 规范中引入的 DataSource 对象。建立合用连接通常要比建立不合用连接要省时省力,它们允许更有效地使用系统资源,能使管理员对一些特性进行自动化处理,这些特性包括:一个应用程序能保持多久的非活动连接;空闲的连接在关闭之前能够在池中保留多久;一个池在到达它的最大极限状态前能容纳多少连接。
我们使用这两种连接来构建会话 EJB 和 Web 服务,而且在这里我们还将研究每种连接的代码示例。但是,请注意:除了测试用途外极少使用不合用连接。就算不考虑性能和资源问题,不合用连接还能干扰由 EJB 容器自动实现的事务语义,您将会在本文后面发现这一点。
由于合用连接更受推崇,那我们首先就来讨论合用连接。如前面所述,DataSource 对象代表合用数据库连接。在 WebSphere Application Server 和 WSADIE 中,可以使用图形管理工具将 DataSource 添加到 Web Application Server 中。一旦服务器启动,程序员就使用 JNDI 服务查找感兴趣的 DataSource 并调用与此相关的用于获取合用连接的方法。 清单 1说明了这个过程是如何进行的。该技术可以用于任何服务器端的 Java 组件或基于 Java 的 Web 服务。
清单 1. 获取合用连接
// import any necessary packages
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
// sample method using a DataSource connection
public void sampleDS() throws Exception {
. . .
// set the user ID and password.
// these values must correspond to values valid at the target data source
String userid = "user1";
String pwd = "pass1word";
// declare a variable for the connection
Connection con = null;
try {
// get the initial context using default values
Context ctx = new InitialContext();
// look up the desired data source
DataSource ds = (DataSource) ctx.lookup("jdbc/Federated");
// get a connection using a specific user ID and password
con = ds.getConnection(userid, pwd);
...
}
// handle any exceptions
catch (Exception e) {
...
}
// any acquired resources should be released here
finally {
try {
// release the connection
if (con != null) { con.close(); }
...
}
...
}
// end the sample method
}
建立不合用连接无需使用 JNDI 服务。程序员不从 Web 应用程序服务器获取初始上下文并寻找给定的名称,而是装入特定于他们的 DBMS 的 JDBC 驱动程序管理器。接下来,他们从 DriverManager 类获取连接。这个逻辑和产品中携带的 DB2 Java 应用程序样本中的逻辑一样。为了完整性起见,我们在 清单 2中提供了用于使用 JDBC 1.0 风格的技术建立不合用连接的代码样本。但是,当构建 Web 应用程序服务器生产级组件时请避免使用这些类型的连接。它们会浪费系统资源,导致不必要的开销,还可能干扰由 EJB 容器提供的内置事务支持。
清单 2. 获取不合用连接
// import any necessary packages
import java.sql.*;
....
// sample method using an unpooled connection for DB2 on UNIX or Windows
public void sampleNoDS() throws Exception {
// specify the URL for the target database, as defined to the client
String url = "jdbc:db2:djdb";
// specify a valid user ID for the target database
String userid = "user1";
// specify a valid password for the target database
String pwd = "pass1word";
// declare a variable for the connection
Connection con = null;
....
try {
// load the JDBC driver class
Class.forName("COM.ibm.db2.jdbc.app.DB2Driver").newInstance();
// instruct the JDBC Driver Manager to get a new connection.
// note that we explicitly reference the desired database URL
con = DriverManager.getConnection(url, userid, pwd);
...
}
// handle any exceptions
catch (Exception e) {
...
}
// any acquired resources should be released here
finally {
try {
// close the connection
if (con != null) { con.close(); }
...
}
...
}
// end the sample method
}
如果您是一位有经验的 JDBC 程序员,那么到现在您可能已经注意到某些东西:使用联邦数据不需要任何特殊的编程。这是因为联邦 DB2 实例旨在提供对远程数据的透明访问。在正确配置环境后,程序员可以用使用本地管理的 DB2 数据的方式来使用联邦数据。
访问联邦数据
建立连接后,就可从联邦数据对象中选择、插入、更新或删除数据了。做这项工作的 JDBC 代码和您编写的使用本地 DB2 数据的代码一样。事实上,读代码的人不会知道您正在使用联邦数据,除非他(或她)碰巧知道您的 SQL 语句中引用的“表”其实是别名。
例如,假设我们在联邦 DB2 数据库中创建了一个 DINING 别名以映射到一个名叫 REST(restaurant 的简称)的远程表,在我们的示例环境中,该表位于 Oracle8 的 Oracle 服务器中。我们可以发出类似于下面的 SQL 语句:
create nickname dining for oracle8.oracleuser1.rest
包含在我们的 JDBC 代码中的 SQL 语句只会引用 DINING。下面所摘录的代码创建了一个用于先前建立的连接的查询语句。接下来,它更新了 DINING 别名中的数据并在完成后关闭了该语句。
清单 3. 对别名执行 SQL UPDATE
// declare a Statement object for later use
Statement stmt = null;
...
try {
// establish a connection to the federated database
...
// create the Statement object
stmt = con.createStatement();
// update some data in a nickname
int output = stmt.executeUpdate("UPDATE dining set score=1 where id=12");
...
}
// handle any exceptions
catch (Exception e) {
...
}
// any acquired resources should be released here
finally {
try {
// close the statement
if (con != stmt) { stmt.close(); }
...
}
...
}
当然,更复杂的数据访问操作也都是可能实现的。例如,我们只要通过编写一个引用多个别名的 SQL 语句就能连接(join)来自多个源的数据。也可以构建视图来连接或合并(union)来自多个源的数据,这扩展了使用容器管理持久性的实体 bean 数据建模的可能性。我们将在今后的文章里探讨这个主题。
管理事务
虽然从服务器端 Java 组件和 Web 服务访问数据和从任何 JDBC 应用程序访问数据一样,但事务管理却需要更密切的关注。例如,EJB 编程模型要求会话 bean 开发人员为他们的 bean 声明事务属性。 容器管理的事务属性最常用,因为它将事务管理职责委托给 EJB 容器。这样,EJB 程序员不需要在他们的 bean 中硬编码 begin/end 事务指令(包括 commit/rollback 指令)。而是通过为他们的 bean 的事务属性特性设置部署描述符来声明这些信息。EJB 容器在运行时自动实施适当的事务语义。
EJB 1.1 规范为支持的容器管理的事务定义了几个不同的事务属性,总结如下。有关详细信息,请参阅 EJB 1.1 规范。
Required
将在有效的事务上下文中调用 EJB 方法。如果方法被已经拥有事务上下文的客户机调用,那么 EJB 方法会在那个事务内执行。如果方法不是在现有的事务上下文中被调用,那么要启动新的事务并执行 EJB 方法。当 EJB 方法完成时 EJB 容器自动尝试提交事务。
RequiresNew和 Required
的相似之处在于,EJB 方法要在事务上下文中执行。但是,这种方法会始终在新的上下文中执行。因此,如果这种方法被已有事务上下文的客户机调用,那么会暂挂现有的事务且启动新的事务。当 EJB 方法完成后,容器会自动提交事务并继续执行暂挂的事务。
NotSupported
EJB 方法会被“未指定的事务上下文”所调用。事务语义可能根据所使用的容器实现(也就是说,供应商产品)的不同而不同。
Supports
特定的操作会根据 EJB 客户机事务上下文的不同而不同。如果客户机已有事务上下文,那么这种情况的处理和 Required的处理方式一样。如果客户机缺少事务上下文,那么这种情况的处理和 NotSupported中的处理方式一样。
Mandatory
EJB 方法必须在客户机的事务上下文中被调用。如果客户机缺乏事务上下文,那么容器抛出异常。如果客户机有事务上下文,那么这种情况的处理和 Required中的处理方式一样。
Never
特定的操作会根据 EJB 客户机的操作上下文的不同而不同。如果客户机有事务上下文,那么容器抛出异常。如果客户机缺少事务上下文,那么这种情况的处理和 NotSupported的处理方式一样。
另外,会话 bean 程序员可以将他们的事务声明为 BeanManaged 并编写使用 javax.transaction.UserTransaction 接口(Java 事务 API(Java Transaction API)的一部分)的代码,以此为事务的开始和结束划分界线。但是,许多 EJB 架构设计师尽量避免使用 bean 管理的事务,除非特定的业务需求规定他们这么做。允许 EJB 容器使事务管理自动化能够减少编码和测试要求。这里我们将只考虑容器管理的事务。
然而,其它的 Web 应用程序组件没有自动实施事务的方法。因此如果您正在开发 Web 服务、servlet 或 JSP,那您必须在自己的代码内管理事务。
如前所述,最好使用合用连接(基于 DataSource 对象)进行数据访问。这不仅有助于提高性能和节约系统资源,还避免了有关事务语义尤其是 EJB 的问题。使用不合用连接,可能会在 EJB 容器期望进行的事务工作和您的 EJB 正在“私下”执行的工作之间引起冲突。如果单独运行您的 EJB,您不会注意到任何问题,但是当您的 EJB 参与涉及其它 EJB 的工作时,您可能会遇到事务不一致性问题。最好让一个组件 - EJB 容器 - 承担所有的事务管理职责,而不要试图将协调一个事务的工作分摊给多个组件,其中的一些组件可能是您自己编写的。
那么所有这些意味着什么呢?这有一些我们开发访问持久数据的 Web 应用程序组件时所要遵循的方针:
使用您的 Web 应用程序服务器所支持的合用(DataSource)连接。显式设置 JDBC autoCommit() 方式。该设置决定在每个 SQL 语句后是否自动发出 commit 语句。缺省值设置成 true 。对值进行显式设置可避免混淆并使您的代码更易于维护。
如果要写会话 EJB,那么就把 autoCommit() 设置成 false 并允许 EJB 容器代表您的 bean 管理事务。另外,将 bean 的部署描述符中的事务属性设置成 Required或 Requires_New。
如果是编写非 EJB 的 Web 应用程序组件,那么把 autoCommit() 设置成 true 或 false 都可以,这取决于您的应用程序的需要。如果您将它设置成 false,请确保必要时显式地 commit() 您的工作。
最后,DB2 V8.1 现在对在每个事务中对单一数据源执行写操作进行了限制。如果您想使用它的联邦 DBMS 功能,您必须在开发服务器端 Java 组件和 Web 服务时想到这一点。
创建会话 bean 以访问联邦数据
既然您已经熟悉了从 Web 应用程序组件对联邦数据进行访问所涉及的基本问题,那就让我们讨论怎样创建做这些事的会话 EJB。我们将看到如何使用 WSADIE 来构建会话 EJB,同时讨论所生成代码的关键部分。
当使用 WSADIE 时,切换到 J2EE 透视图并照常创建一个 EJB 项目和会话 EJB。如果有必要,请参考联机文档以帮助您完成这些任务。当创建了无状态会话 bean 后,您现在可以为新的访问联邦数据的业务方法编写代码。 清单 4说明了如何使用合用连接来构建会话 EJB 方法以访问联邦数据。这个代码样本按 参考资料中所描述的那样“按现状”提供给您。
QueryNickname 会话 EJB 包括了 updateDining() 业务方法。该方法驻留在 QueryNickname bean 实现类中。该方法从先前在 WebSphere Application Server 测试环境中定义成 jdbc/Federated的数据源处获得合用连接,该数据源映射到名为 jdbc:db2:djdb的 JDBC URL 上。对联邦别名发出简单的 UPDATE 查询,并将更改的行的计数返回给调用者(尽管在这没有演示,但 SELECT、INSERT 和 DELETE 操作的编码很相似)。最后,释放所获取的资源。请注意,对于使用联邦数据不要求有特殊的编码需求。该示例中所包含的其它方法由 WSADIE 自动生成且符合 EJB 1.1 规范的需求。
清单 4. 用于访问联邦数据的会话 EJB
package session;
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
/**
* Bean implementation class for Enterprise Bean: QueryNickname
*/
/*********************************************************************/
public class QueryNicknameBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext mySessionCtx;
/**
* getSessionContext
*/
public javax.ejb.SessionContext getSessionContext() {
return mySessionCtx;
}
/**
* setSessionContext
*/
public void setSessionContext(javax.ejb.SessionContext ctx) {
mySessionCtx = ctx;
}
/**
* ejbActivate
*/
public void ejbActivate() {
}
/**
* ejbCreate
*/
public void ejbCreate() throws javax.ejb.CreateException {
}
/**
* ejbPassivate
*/
public void ejbPassivate() {
}
/**
* ejbRemove
*/
public void ejbRemove() {
}
// test oracle nickname access via data source
public int updateDining() throws Exception {
// set values for DBMS user ID and password
String userid = "user1";
String pwd = "pass1word";
// declare variables for our Statement and Connection objects
Statement stmt = null;
Connection con = null;
// declare variable for return value: number of rows changed
int output = 0;
try {
// get an initial context
Context ctx = new InitialContext();
// perform JNDI look up of our federated data source
DataSource ds = (DataSource) ctx.lookup("jdbc/Federated");
// establish a connection to the data source
con = ds.getConnection(userid, pwd);
// turn off auto commit mode
con.setAutoCommit(false);
// create a statement for our SQL query
stmt = con.createStatement();
// execute an update statement
output = stmt.executeUpdate("update dining set score=2 where id=87");
// return the count of changed rows
return output;
}
// handle any exceptions
catch (Exception e) {
...
}
// clean up resources
finally {
try {
// release the statement
if (stmt != null) { stmt.close(); }
// release the connection
if (con != null) { con.close(); }
}
catch (Exception e) {
e.printStackTrace();
}
} // end finally block
} // end updateDining
}
先前演示的 bean 实现类只是一个全功能的会话 bean 所要求的软件模块。为使我们的 updateDining 方法对于调用者来说是可访问的,必须将它添加到 bean 的 Remote 接口中。在 WSADIE 中,这能通过 J2EE 透视图轻易做到。如果有必要,请参考产品文档以帮助您完成该步骤。完成后,bean 的 Remote 接口如 清单 5所示。
清单 5. QueryNickname 企业 Bean 的 Remote 接口
package session;
/**
* Remote interface for Enterprise Bean: QueryNickname
*/
public interface QueryNickname extends javax.ejb.EJBObject {
// test oracle nickname access via data source
public int updateDining() throws Exception, java.rmi.RemoteException;
}
bean 的 Home 接口在我们的工作中没有变化。由 WSADIE 生成的样本代码如 清单 6所示。
清单 6. QueryNickname 企业 Bean 的 Home 接口
package session;
/**
* Home interface for Enterprise Bean: QueryNickname
*/
public interface QueryNicknameHome extends javax.ejb.EJBHome {
/**
* Creates a default instance of Session Bean: QueryNickname
*/
public session.QueryNickname create() throws javax.ejb.CreateException,
java.rmi.RemoteException;
}
创建 Web 服务以访问联邦数据
正如您所见,可以在会话 EJB 之中使用标准的 JDBC 编程技术以访问联邦数据。Web 服务以及其它应用程序服务器组件,都能使用标准的 JDBC 编程技术进行开发以访问联邦数据。事实上,Web 服务所要求的 Java 源代码和会话 bean 中的业务方法所要求的源代码几乎一样。
WSADIE 能使您基于多种软件组件构建 Web 服务,这些软件组件包括 EJB 和标准 JavaBean。后者有别于 EJB,尽管名字听起来很相似(有关 JavaBean 的详细信息,请参阅来自 Sun Microsystems 的规范)。构建派生自 JavaBean 的 Web 服务可能是最简单的开发技术之一,我们将在这里对此进行讨论。
当使用 WSADIE 时,切换到 Web 透视图并照常创建 Web 项目。在该项目中,创建您所选择的 JavaBean 和适合用做 Web 服务的业务方法。对于测试来讲,创建一个 Java 类,它有一个不带参数的构造器并且返回 String 或其它原始类型作为输出的简单业务方法,这就足够了。遵循标准 WSADIE 过程从该 JavaBean 生成和测试 Web 服务(要调用一个向导以指导您完成该过程,突出显示 JavaBean 类,单击鼠标右键,然后选择 New -> Web Service)。如果有必要,请参考 WSADIE 联机文档以帮助您完成该任务。
清单 7演示了一个带有 addRow() 方法的 SimpleWebQuery 类,我们把该方法用作 Web 服务的基础,请注意这个方法建立了与 DataSource 的合用连接,该 DataSource 早先在 WebSphere 测试环境中定义成 jdbc/Federated。我们的方法仅仅将一行插入到别名中,该别名映射到一个 Microsoft SQL Server 表中,然后释放已获取的资源。对于使用联邦数据来说,不要求编写特殊的代码。
清单 7. SimpleWebQuery 类
// import required packages
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
public class SimpleWebQuery {
// We need a zero-argument constructor
public SimpleWebQuery() {
super();
}
// This method will insert a single row into a nickname.
// For production applications, we'd want to make its INSERT
// statement more flexible.
public String addRow() {
Connection con = null;
Statement stmt = null;
String reply = null;
String user = "user1";
String pwd = "pass1word";
try {
// get a pooled connection
InitialContext context = new InitialContext();
DataSource ds = (DataSource) context.lookup("jdbc/Federated");
con=ds.getConnection(user, pwd);
con.setAutoCommit(true);
// insert a row into the database
stmt = con.createStatement();
stmt.executeUpdate("Insert into DINING values
(85, 'New Restaurant', 2)");
reply = new String("Insert complete.");
}
catch (Exception e) {
// handle any exceptions
...
}
finally {
// release all acquired resources
try {
if (stmt != null) { stmt.close(); }
} catch (Exception e) { }
try {
if (con != null) { con.close(); }
} catch (Exception e) { }
return reply;
}
} // end addRow
}
扩展项目的前任软件技术讲师。她在北美、南美、欧洲和中东作过许多技术主题的演讲。
关于作者
C. M. Saracco是 IBM 硅谷实验室的资深软件工程师,还是 UC Santa Cruz 扩展项目的前任软件技术讲师。她在北美、南美、欧洲和中东作过许多技术主题的演讲。