配置 SCA 组件参与 WS-AT 全局事务
http://tech.ddvip.com 2008年07月07日 社区交流 收藏本文
内容摘要:事务 (transaction) 支持对于构建可靠的分布式应用至关重要。面向服务的组件体系结构 (SCA) 为我们提供了一个与实现无关的开发架构,SCA 组件是构建 SOA 应用的基本单位,本文将介绍 SCA 对事务的支持,以及如何使用 WebSphere Integration Developer (WID) 开发与配置支持全局事务的 SCA 应用。
引言
本文将讲述如何用 WID 开发运行于 WebSphere Process Server(WPS) 上的支持全局事务的 SCA 应用。首先将介绍事务相关概念,接着讲述 SCA 对事务的支持,最后我们通过一个示例演示如何在组件层次制定事务属性,开发支持 WS-AT 全局事务的 SCA 应用,。
概念介绍
事务 :保证一组对于资源的更新活动以原子的方式执行。也就是说,要么事务中所有的资源更新都被执行,其结果被永久保存;要么所有活动都不执行。
Resource Manager Local Transaction (RMLT):RMLT 是从资源管理器角度来看,通过单一连接使用资源的局部事务。支持 RMLT 的资源管理器,包括通过资源适配器 (Resource Adapter) 进行访问的 EIS,通过 JDBC DataSource 访问的关系数据库,JMS 队列,等等。
Global Transaction( 全局事务 ):当一个应用使用到多个资源时,需要一个外部的事务管理器通过全局事务来协调对各个资源的更新。在 J2EE 中,使用 BMT(Bean Managed Transaction) 的 EJB 组件,应用程序客户端组件,web 组件等可以通过 Java Transaction API(JTA) 的 userTransaction 接口来创建 / 参与到全局事务中;采用 CMT(Bean Managed Transaction) 的 EJB 组件则由容器负责划分事务。
WS-AT: Web service atomic transaction (WS-AT) 是 IBM,Microsoft, BEA 等提出的在 web service 应用之间使用分布式全局事务的协议,全局事务的参与者通过两阶段提交协议来协调事务状态,确保所有事务参与者能够达到一致的状态 , 即所有参与者都回滚或者提交。WS-AT 本身并没有定义新的事务接口,全局事务的划分仍然通过标准的 JTA 接口来定义。当运行于全局事务的 J2EE 应用程序发起 web service 请求时,事务管理器将在 SOAP header 中自动插入对应的 WS-AT CoordinationContext。web service 目标组件接受到请求时,其事务管理器将根据发送过来的 WS-AT CoordinationContext 创建从属于此全局事务的 JTA 事务,从而 web service 的各个参与者都运行于同一个全局事务上下文中。
WPS 对事务的支持 :WPS 从 version 6.0 开始实现了对 WS-AT 的支持。WPS 可以作为事务管理器来协调全局事务,也可以作为全局事务参与者参与到全局事务中,同时也为 RMLT 提供运行环境。
SCA 中的事务的支持
Service Component Architect (SCA) 中,组件拥有标准的接口 (WSDL,java interface 等 ),组件的实现形式可以是 BPEL,POJO,business rule 等等。这些 SCA 组件可以导出为外部应用程序所使用,也可以导入外部组件为自身使用。SCA 组件对于事务的支持通过 QoS 来指定。开发者在 SCA 组装的时候可以为其指定事务相关的 Qualifier,SCA runtime 将根据事务 QoS 属性在运行时提供相应的事务支持。WID 为 SCA 组件提供了强大的开发工具。对于 SCA 组件的事务属性定制,WID 同样提供了方便的编辑工具。
具体来说,在开发和组装 SCA 的时候可以在 Interface(接口)和 implementation(实现)两个方面为组件指定事务支持属性:
Component Implementation Qualifier for transaction:
组件实现的 Qualifier 属性指定了组件在运行时对于安全性,事务等 QoS 的要求。其中 "Transaction' 属性表明了组件执行时对活动的逻辑划分,其取值与意义如下:
Global:若客户请求传播了全局事务上下文,则组件运行于此全局事务中;若不存在已有的全局事务,则会新建一个全局事务。
Local:组件运行于一个局部事务中,该事务不能跨域容器边界。
Any:若存在全局事务上下文,则组件将运行于此全局事务中;否则组件将运行于局部事务中。
Component interface Qualifier for transaction:
组件接口的 Qualifier 是组件对外部的 QoS 声明,是组件与其客户端交互的协约。其中的 "Join Transaction" 属性声明了组件与客户端参与事务的特性,其取值与意义如下:
True:组件运行时容器将参与到任何客户端传播过来的事物中。
False:组件运行时容器不参与到客户端传播的事务中。
接口和实现的事务属性一起决定了组件运行时的事务特征:
| Interface - Join Transaction qualifier | Implementation - Transaction Value qualifier | 组件事务行为 |
| True | Global | 组件将运行于传播来的全局事务中,否则将新建一个全局事务 |
| True | Local | 不兼容,在 WID 中将导致检查错误 |
| True | Any | 组件将运行于传播来的全局事务中,否则将运行于本地事务中 |
| False | Global | 组件将运行于新建的全局事务中 |
| False | Local | 组件将运行于本地事务中 |
| False | Any | 组件将运行于本地事务中 |
在 SCA 应用中应用 WS-AT
本小节通过一个示例介绍如何为 SCA 组件定制全局事务支持。
场景说明
示例模拟这样一个简单的银行转帐流程,包括取款 (withdraw balance) 和存款 (add balance) 两个阶段,这两个阶段的功能分别由两个 SCA 组件实现,如【图一】所示。AccountTransfer 组件由 BPEL 流程实现,组装取款与存款组件以完成转帐功能,如【图二】所示。我们将通过配置 SCA 事务支持,以保证存款与取款两组件的操作结果一致,即两者都提交或者两者都回滚。
图一 Account Transfer 服务组装图

图二 Account Transfer BPEL 流程图

应用实现
存款组件由 java 实现,当交易额大于 1000 时抛出 Exception。其主要代码为:
public String add(String account, Integer amount) throws Exception {
//TODO Needs to be implemented.
if(amount.intValue()>1000){
throw new Exception("tranfer amount"+amount.intValue()+"
is too large at a time");
}
return "OK";
}
取款组件由 java 实现,并导出为 web service,为 AccountTransfer 流程所调用。取款组件从数据库中对应的帐号减去取款数额,其主要代码为:
public String withdraw(String account, Integer amount) throws
NamingException, SQLException {
//TODO Needs to be implemented.
Connection con = this.getConnection_DS();
Statement st = con.createStatement();
String sql="update account set amount=amount-"+amount.intValue()+"
where accid='"+account+"'";
st.executeUpdate(sql);
st.close();
con.close();
return "SUCC";
}
private Connection getConnection() throws NamingException, SQLException {
Connection con = null;
DataSource ds = null;
ds = (DataSource) new InitialContext().lookup("jdbc/account");
con = ds.getConnection();
return con;
}
SCA 事务配置
本部分介绍如何对 SCA 进行全局事务配置。我们的应用包括三个 SCA 组件:转帐组件,由 BPEL 实现;取款组件和存款组件均由 Java 实现。我们将根据前面介绍的概念为组件配置事务 QoS 属性。显然,要让三个组件参与到全局事务中,组件实现的 Transaction 属性应该设为”Global”, 组件接口的”Join Transaction”属性应该设为”True”。
在 WID 中导入项目交换文件 accounttransfer.zip , 切换至 Business Integration 视图,如【图三】所示。
图三 AccountTransfer 项目视图

在 Assembly Diagram 中打开 AccountTransferModule,选择”addBalanceComp”组件,在”Properties”页中依次选择”Details”=>”Interfaces”=>”addBalance”=>”Qualifiers”, 为其添加”Join transaction” QoS 属性,其值设为”true”,如【图四】所示。
图四配置存款组件接口事务属性

选择”Implementation”=>”Qualifiers”, 为其添加”Transaction” QoS 属性 , 其值设为”Global”,如【图五】所示。
图五配置存款组件实现事务属性

3. 按照与步骤 2)同样的方式,为”withdrawBalanceWSImport”导入添加”Join Transaction”QoS 属性,其值设为”true”; 在 Assembly Diagram 中打开 DelBalanceModule, 为”withdrawComp”组件在 Interface 上添加”Join transaction” QoS 属性,其值设为”true”,在 implementation 上添加”Transaction” QoS 属性 , 其值设为”Global”。
4. 对于实现为 BPEL 的组件,我们可以看到全局事务属性默认已经被选上
5. 保存设置,重新 build 项目。
WS-AT 事务配置
本部分介绍如何在 WID 中为应用配置 WS-AT 全局事务支持,关于 WS-AT 更详细的介绍,请参考【文献 1】。
在 WID 中切换至”J2EE”视图,在”Project Explorer”中选择“Dynamic Web Projects” => ”AccountTransferModuleWeb”, 双击”Deployment Descriptor”, 在”Servlets” Tab 中选中” AccountTransferServiceExport1_AccountTransferServiceHttpPort”,在”Global Transaction”栏中选上”Send Web Service Atomic Transaction on requests”, 如【图六】所示。这表明 AccountTransfer 应用将在调用 Web Service 的请求中发送 WS-At Context。
图六为 AccountTransfer 应用配置 WS-AT

创建数据源
1. 在 DB2 中创建数据库 account。在 account 数据库中按照如下 SQL 创建 account 表:
CREATE TABLE "ADMINISTRATOR"."ACCOUNT" (
"ACCID" VARCHAR(10) NOT NULL ,
"AMOUNT" INTEGER NOT NULL );
ALTER TABLE "ADMINISTRATOR"."ACCOUNT"
ADD CONSTRAINT "PK_ACCID" PRIMARY KEY
("ACCID");
2. 向 account 表中添加测试用数据:
Insert into account values (‘acc001’,10000);
Insert into account values (‘acc002’,10000);
3. 在 WPS 管理控制台上为 account 数据库创建 jdbc 数据源,其 JNDI 为”jdbc/account”, 在这里我们使用”DB2 Universal JDBC Driver Provider(XA)”类型数据源。
部署与测试
1. 将 AccountTransferModule 和 DelAccountModule 导出为 EAR,部署到 WPS 上。
2. 在 WID 中用 Web Service Explorer 测试 AccountTransfer 服务如下:
测试一:从账号 acc001 转帐 500,服务返回成功。输入与结果如【图七】所示:
图七测试成功 case

测试二:从帐号 acc002 转帐 2000,服务返回异常,在数据库中打开 account 表,可以发现账户余额没有发生变化。这是因为交易额大于 1000,存款组件抛出异常,处于 WS-AT 全局事务的取款组件所作操作被回滚。服务返回消息为:
<soapenv:Body>
<soapenv:Fault>
<faultcode>soapenv:Server.generalException</faultcode>
<faultstring>
<![CDATA[
javax.transaction.TransactionRolledbackException: ; nested exception is:
com.ibm.websphere.csi.CSITransactionRolledbackException: Transaction marked
rollbackonly
]]>
</faultstring>
</soapenv:Fault>
</soapenv:Body>
注意事项
参与 WS-AT 全局事务的数据源必须支持两阶段提交协议,例如支持 XAResource 接口的数据源。
参与全局事务的组件,其事务的提交由全局事务管理器来决定,不能在组件中使用 Connection.commit 方法,这样将导致运行时错误。
WS-AT 适用于 short duration 的流程。由于两阶段提交协议通过对资源加事务锁来实现,不适合 long running 的流程,而通常采用 compensation 的方式
对于应用了全局安全的 WPS,您需要进行额外的配置以支持 WS-AT, 请参考【文献 2】中对于 WS-AT 部分的说明
总结
本文介绍了 SCA 中的事务相关概念,通过本文的例子可以看到,SCA 提供了一个与实现无关的开发架构,不论其实现为 BPEL 还是 POJO,我们都可以方便的通过其事务 QoS 属性,声明式地配置组件的事务行为。
来源:ibm 作者:周志远 责编:豆豆技术应用