俞良军
软件工程师,
2003 年 8 月 WebSphere Studio提供了自动生成Web服务框架代码的向导,帮助开发者减少耗费在编写Web服务框架代码上的时间,得以集中精力处理与应用核心逻辑有关的事务。本文示范了如何在WebSphere Studio环境中,从DB2存储过程出发构建一个简单的库存管理服务。
Web服务有着许多优点:它以标准的消息传递协议为基础,提供了一种模块化、自我描述、自我包容的业务逻辑共享机制;由于业务逻辑从客户端和数据库剥离,方便了多种应用共享业务逻辑。
然而,由于Web服务是一种新兴的技术,构建基于Web服务的应用也必须付出一定的代价:与Web有关的标准,例如SOAP、UDDI和JAX-RPC等仍在快速发展变化之中,构建一个Web服务应用涉及诸多因素,包括客户端代码、消息协议、WSDL、安全、注册、部署等等。对于开发者来说,保持应用稳定性与新技术/标准不断发展之间的平衡很不容易。
WebSphere Studio提供了自动生成Web服务框架代码的向导,帮助开发者减少耗费在编写Web服务框架代码上的时间,得以集中精力处理与应用核心逻辑有关的事务。本文示范了如何在WebSphere Studio环境中,从DB2存储过程出发构建一个简单的库存管理服务。
一、应用概况
一家超市分店要通过网络查找总店的库存是否足够,如库存充足,则更新总店仓库的库存总量,即减去提货数量。我们用存储过程来实现这一业务逻辑,这是考虑到网络通信是许多联机应用最大的性能瓶颈所在,使用存储过程有利于减少应用通过网络访问数据库的次数。此外,使用存储过程还有其他许多好处,例如由于业务逻辑的集中化,应用的维护和更新变得更加方便,一旦修改了存储过程,修改结果会立即对所有客户程序生效;又如数据库管理系统本身就提供了强健的安全和管理机制,简化了整个应用的安全和管理。
具体地说,本文库存管理数据库存储过程的逻辑流程为:
- 根据商品ID查找inventory表,获得商品的当前库存量。
- 比较当前库存量与提货数量。
- 如库存充足则更新inventory表,从现有库存减去提货数量。
- 查询inventory表,获得商品的详细说明、计划送货时间。
该存储过程需要两个参数:itemId,表示商品编号;Quantity,表示提货数量。
假设库存数据保存在SAMPLE DB2数据库上。下面是创建库存表INVENTORY和插入样本数据的SQL命令:
CREATE TABLE SCHEMA1.INVENTORY2 ( ITEMID INTEGER NOT NULL ,
DESCRIPTION CHARACTER (20) , QUANTITY INTEGER , ETA CHARACTER (10)
) IN USERSPACE1
insert into schema1.inventory (itemid, description,quantity,eta) values (100,'abc',300,'20')
insert into schema1.inventory (itemid, description,quantity,eta) values (101,'def',301,'20')
|
其中ITEMID列表示商品编号ID,DESCRIPTION列是商品的描述,QUANTITY列是库存数量,ETA列是发货期限说明。
二、创建存储过程
直接手工构造和部署存储过程有时比较麻烦。WebSphere Studio集成了一组辅助创建存储过程的工具,极大地简化了这一工作。利用WebSphere Studio里的各种存储过程工具,我们可以新建存储过程、修改现有的存储过程、在DB2服务器上部署和注册存储过程、运行/调试存储过程、从DB2服务器删除存储过程,等等。
创建存储过程之前首先要建立一个数据库连接,这可以借助WebSphere Studio的连接向导完成。如图一,输入数据库名称、用户标识、数据库供应商类型、JDBC驱动程序、过滤器(可选,用于排除要导入的数据库信息),点击"完成"导入数据库信息,接下来就可以启动存储过程向导构造Java存储过程。
图一:连接到DB2数据库
库存管理存储过程由三个SQL语句构成:一个查询库存的SELECT语句,一个在库存充足时更新库存数据的UPDATE语句,还有一个SELECT语句用来查找商品的详细说明和送货时间。在Java存储过程向导中,如图二,将存储过程的类型指定为"生成多个SQL语句",然后点击"SQL助手"按钮启动SQL向导,依次完成三个SQL语句。
图二:创建存储过程的SQL语句
运行好Java存储过程向导后,向导自动创建包含Java存储过程的.java文件。自动创建的代码首先连接指定的数据库,然后执行三个SQL语句。按照前面的说明调整向导自动创建的代码逻辑,使其首先检查库存,当库存充足时更新库存减去提货数量。修改好之后的Java存储过程如下所示:
/**
* JDBC 存储过程 SCHEMA1.UPDATEINVENTORY
*/
import java.sql.*; // JDBC 类
public class UPDATEINVENTORY {
public static void UPDATEINVENTORY (
int quantity,int itemId, ResultSet[] resultSet )
throws SQLException {
// 获取与数据库的连接
Connection con = DriverManager.getConnection("jdbc:default:connection");
//查询指定商品的当前库存
String sql =
"SELECT SCHEMA1.INVENTORY.QUANTITY"
+ " FROM SCHEMA1.INVENTORY"
+ " WHERE SCHEMA1.INVENTORY.ITEMID = ?";
PreparedStatement stmt = con.prepareStatement(sql);
stmt.setInt(1, itemId);
stmt.execute();
ResultSet rs = stmt.getResultSet();
rs.next();
int currentQuantity = rs.getInt(1);
// 库存足够吗?
if (currentQuantity > quantity) {
// 从现有库存减去提货数量
int newQuantity = currentQuantity - quantity;
// 更新库存数据
sql =
"UPDATE SCHEMA1.INVENTORY SET QUANTITY = ? "
+ " WHERE SCHEMA1.INVENTORY.ITEMID = ?";
stmt = con.prepareStatement(sql);
stmt.setInt(1, newQuantity);
stmt.setInt(2, itemId);
stmt.executeUpdate();
// 提取该商品的详细信息
sql =
"SELECT SCHEMA1.INVENTORY.DESCRIPTION,SCHEMA1.INVENTORY.QUANTITY, SCHEMA1.INVENTORY.ETA "
+ " FROM SCHEMA1.INVENTORY"
+ " WHERE SCHEMA1.INVENTORY.ITEMID = ?";
stmt = con.prepareStatement(sql);
stmt.setInt(1, itemId);
stmt.execute();
resultSet[0] = stmt.getResultSet();
}
}
}
|
接下来要做的是构建存储过程并将它注册到DB2服务器。构建存储过程的步骤是:在"数据定义"视图中用鼠标右键点击UPDATEINVENTORY存储过程,然后选择菜单命令"构建"。这时,系统将编译Java源代码,如编译通过,则在数据库服务器上注册存储过程。在构建存储过程的过程中,数据库输出视图将显示出当前的构建进度,如图三;如果构建过程中发现错误,错误信息也会在数据库输出视图中显示出来。
图三:构建存储过程
数据库输出视图的左边窗格显示出已执行的操作,右边窗格包含三页:消息,参数,结果。消息页面的内容就是数据库服务器输出到控制台的内容,如果执行操作的时候遇到错误,这里将显示出错误代码或某些跟踪信息。参数页面显示出输入参数、输出参数以及它们的值。结果页面显示出执行操作后返回的结果。如果有多个结果集,可以用箭头在多个结果集之间翻页。
用鼠标右键选择存储过程,然后选择菜单命令"运行",图四是运行设置向导要求输入参数值的界面,本例我们要提取编号为100的商品,提货数量12。存储过程的运行结果将显示在数据库输出视图的"结果"页。
图四:输入运行存储过程的参数
三、构建Web服务
现在我们已经顺利构建和测试存储过程,接下来就可以将它封装成Web服务,以便通过Internet调用。为了将存储过程作为Web服务运行,我们需要Web服务对象运行时框架(Web Services Object Runtime Framework),简称WORF。WORF包含在WebSphere Studio之中,但也可以单独下载,它提供了一个构建XML Web服务和访问DB2的环境。WORF支持标准的SOAP协议,它利用DADX(Document Access Definition Extension)文件描述可以通过Internet调用的SQL操作。
除了SOAP请求,WORF还支持HTTP GET和POST操作。当出现对服务的请求时,WORF装入请求中指定的DADX文件,连接到DB2数据库,运行SQL命令,提交数据库事务,然后把结果格式化成XML文档(必要时进行数据类型转换),最后向请求者返回结果。此外,WORF还可以用来生成WSDL、XML模式、文档或测试页面。
3.1 创建DADX组
每一个DADX文件都必须属于一个DADX组。DADX组保存在Web应用的WEB-INF/classes/groups目录,其中包含了数据库连接参数等DADX组内各个DADX文件共享的信息。
DADX组可以用Web服务DADX组配置向导创建,如图五所示。本例中,我们把组的名称定义为InventoryDadxGroup,把DB URL改成jdbc:db2:SAMPLE,使该组DADX文件能够访问到正确的数据库,然后设置访问SAMPLE数据库的用户标识和密码。向导把组定义信息保存在该组的group.properties文件,同时向导还会自动更新Web应用的部署描述符web.xml,保存必要的信息,例如该WORF Web应用的Servlet映射信息等。
图五:设置DADX组
3.2 创建DADX文件
创建好DADX组之后,接下来要做的是创建DADX文件。WebSphere Studio提供了一个DADX文件向导帮助我们创建DADX文件。在DADX文件向导中,我们可以选择要封装成Web服务的SQL语句和DAD文件,向导自动生成相应的DADX操作。下面就是调用UPDATEINVENTORY存储过程的DADX文件Inventory.dadx。
<?xml version="1.0" encoding="UTF-8"?>
<dadx:DADX xmlns:dadx="http://schemas.ibm.com/db2/dxx/dadx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xsi:schemaLocation=
"http://schemas.ibm.com/db2/dxx/dadxdadx.xsd">
<dadx:result_set_metadata rowName="result" name="detail">
<dadx:column name="DESCRIPTION" type="VARCHAR" nullable="true" />
<dadx:column name="QUANTITY" type="INTEGER" nullable="true"/>
<dadx:column name="ETA" type="VARCHAR" nullable="true"/>
</dadx:result_set_metadata>
<dadx:result_set_metadata rowName="result" name="ignore">
<dadx:column name="QUANTITY" type="INTEGER" nullable="true"/>
</dadx:result_set_metadata>
<dadx:operation name="UpdateInventory">
<dadx:call>
<dadx:SQL_call>CALL UPDATEINVENTORY(:quantity, :itemId)</dadx:SQL_call>
<dadx:parameter name="quantity" type="xsd:int" kind="in" /><dadx:parameter name="itemId" type="xsd:int" kind="in" />
<dadx:result_set name="results1" metadata="ignore" />
<dadx:result_set name="results2" metadata="detail" />
</dadx:call>
</dadx:operation>
</dadx:DADX>
|
图六是在WebSphere Studio中打开的Inventory.dadx文件的"设计"视图,更清楚地显示出了各个元素之间的关系。
图六:DADX文件结构
其中<dadx:SQL_call>标记包含了对存储过程UPDATEINVENTORY的调用,<dadx:parameter>标记定义了提供给存储过程的两个参数,<dadx:result_set>标记定义了存储过程返回的结果集。<dadx:result_set_metadata>标记定义了结果集的元数据,包括列的数据类型和名称。由于CALL语句的JDBC元数据不包含结果集的元数据,因此这些信息必须在DADX文件中定义。
3.3 从DADX文件构建Web服务
定义好DADX组和DADX文件之后,接下来就可以启动Web服务向导,从DADX文件创建Web服务,参见图七。这个向导其实就是从JavaBean或EJB创建Web服务的向导,只是现在我们在Web服务类型中选择了"DADX Web服务"。在Web服务向导接下来的对话框中,指定前面为存储过程创建的Inventory.dadx文件,然后在Web服务测试对话框中选中"测试生成的代理"选项,这样向导就会生成一组用来测试DADX Web服务的JSP页面。
图七:构建DADX Web服务
四、测试Web服务
Web服务向导的生成过程结束后,WebSphere Studio打开测试页面,如图八所示,测试页面列出了一系列可供调用的方法。点击UpdateInventory(int,int)方法,窗口右上方显示出该方法的输入参数。输入商品ID、提货数量两个参数之后点击Invoke按钮,窗口右下方显示出调用UPDATEINVENTORY存储过程的结果。
图八:测试DADX Web服务
综上所述,WebSphere Studio提供的诸多工具不仅简化了存储过程的创建,而且我们还可以从存储过程出发方便地构造出Web服务。其中主要的两个工具是WORF框架和DADX文件。DADX文件不仅可以调用存储过程,而且还可以定义其他操作,例如更新、查询、插入、删除等SQL操作;如果用DB2 XML Extender向数据库保存XML文档或从数据库提取XML文档,还可以指定storeXML和retrieveXML之类的操作。
关于作者
俞良军是自由职业者,软件工程师。可以通过 lt00002@21cn.com与他联系。 |
|