随笔 - 181, 文章 - 2, 评论 - 85, 引用 - 0
数据加载中……

使用 SDO 和 JDBC Data Access Service 启用SOA

本文对随 IBM® Rational® Application Developer V6 一起提供的数据访问服务(Data Access Services,DAS)进行了概述,并对这些访问服务在使用服务数据对象(Service Data Object,SDO)的面向服务的体系结构 (SOA) 中扮演的角色进行了说明。

引言

IBM Rational Application Developer for WebSphere® Software V6 所包含 JDBC Data Access Services 提供了对面向服务的体系结构的持久化层的标准化访问。数据访问服务 (DAS) 与服务数据对象 (SDO) 密切相关,因此要了解 DAS 的概念,首先需要了解一下 SDO。

在本文讲述的高级部分,将给出一个端到端的示例应用程序,该应用程序使用适合开发人员和架构师使用的 JDBC DAS。该示例使用 XML 对象关系映射信息保存对 SDO 对象图的更改。(请参阅参考资料,以获得有关 SDO 的更多信息。)

什么是 SDO?

服务数据对象(Service Data Objects,SDO)是一项新兴标准,用于表示企业应用程序中的数据。SDO 是信息的容器,设计用于提升开放标准和互操作性。SDO 提供了在整个企业应用程序中表示信息的方法,包括表示层、业务逻辑层和此类层之间的通信,如图 1 所示。


图 1. SDO 概述
图 1. SDO 概述

服务数据对象的主要特性包括:

  • SDO 可以包含嵌套对象。此功能称为对象图,是一种非常灵活的表示数据的方式。例如,图 2 中的 SDO 就表示一个有各种产品的多个订单的客户:


    图 2. SDO 数据图
    图 2. SDO 数据图
  • SDO 支持 XPath,可以访问其封装的数据。XML 路径语言 (XPath) 是一项开放标准,是由 World Wide Web Consortium (W3C) 制定的,用于从 XML 文档访问数据。例如,可以使用以下字符串访问特定的产品:CustomerOrder/Product[name='MP3Player'],其中,CustomerOrder 为 Customer 和 Order 之间定义的关系。

  • SDO 可以作为 XML 构件或 Java™ 对象存在。借助对 XML 的这项透明支持,直接使用 <datagraph> 标记作为开头来传递 XML SDO,就可以通过 Web 服务(或任何 XML 传输,如 REST 或 XML-RPC)传递 SDO。而且,仅在 SDO v1 中使用更改摘要时,才有必要使用 <datagraph> 标记。在其他所有情况下,可以使用任何标记。

  • SDO 包含更改摘要。SDO 更改摘要作为所有活动的历史记录使用,通过使用此功能,应用程序可以将旧数据和新数据区分开。例如,加入某个客户决定下新订单。接受订单的企业系统由图 3 中的高级组件组成。请注意,包含新订单的 SDO 将从门户服务器传递到后端服务。如果没有更改摘要,后端服务必须将 SDO 中的所有数据放入数据库。不过,由于可以访问 SDO 更改摘要,因此,只需要将新数据放入数据库即可,从而提高后端服务的效率。此外,门户服务器可以通过使用更改摘要来传递更小的 SDO,该 SDO 中仅包含在前端所做的更改。


    图 3. 更改摘要
    图 3. 更改摘要
  • SDO 是开放标准。SDO 1.0 和 2.0 规范均是由 BEA® 和 IBM 联合发布的(请参阅参考资料)。任何组织都可以免费使用和实现这些标准。

什么是 DAS?

数据访问服务 (Data Access Service) 根据 SDO 1.0 标准保存 SDO。DAS 可以采用任何持久化机制实现。例如,Rational Application Developer V6 包括了一个 JDBC DAS 和一个 EJB 实体 Bean DAS,允许采用标准方式将 SDO 保存到各种后端系统,从而提升企业应用程序内的互操作性和标准。


图 4. DAS 概述
图 4. DAS 概述

DAS 是一项新兴的规范,其标准化进程仍在进行之中。现在称为 DAS 的新一轮工作就是即将推出的数据访问服务 (DAS) 标准。可以将 DAS 称为 DAS 2.0。DAS 将对 SDO 2.0 规范形成补充,正在制定之中(DAS 被认为处于 SDO 2.0 规范之外)。







面向服务的体系结构中的数据访问服务

SDO 数据访问服务非常适合作为 SOA 服务公开。他们提供了一个标准,用于构建可以在 SOA 服务间共享的后端服务。例如,假如有一个必须和两个不同业务进行通信的企业系统。这两个业务服务使用完全不同的技术保存信息。如果传递给这些服务的消息为 SDO,则两个服务都可以使用 DAS,企业应用程序可以将其看作同一个组织而进行处理,如图 5 中所示。


图 5. SOA 中的 SDO 数据访问服务
图 5. SOA 中的 SDO 数据访问服务

DAS 还可以提高 SOA 的可维护性。实现 SOA 的一个常见毛病就是会假设公开服务总是有好处的。当公开了服务时,要更改非常困难——对于那些向客户或公众公开某种功能的服务更是如此。例如,假设某家银行有一项已公开了数年的服务,由于政府法规的原因,现在必须对其进行更改——在网上传输的消息必须经过加密,如图 6 中所示。


图 6. SOA 中的 DAS 和可维护性
图 6. SOA 中的 DAS 和可维护性

如果有数百合作伙伴访问该服务,该银行不会轻易更改服务,因为其合作伙伴将不再能与他们开展业务。该银行的最佳选择可能就是构建另一个 99% 冗余的服务,并尽力说服其合作伙伴转而使用新服务。这将使用大量资源,而所得到的业务价值也有限。

将 SDO 和 DAS 配合使用,可以减缓这类问题,因为 SDO 是动态性非常强的消息。如果该银行使用的是 SDO,则可以直接通知其合作伙伴对添加的信息进行加密,而不会更改已公开的服务——只需要更改传递给该服务的消息。如果某个合作伙伴仍然发送旧 SDO XML 格式的消息,通过检查 SDO 的内容(并可能与不兼容的业务合作伙伴联系),银行的应用程序将能够对此类情况作出判断,然后按照以前的方式处理此类信息。







使用 SDO 数据访问服务的业务案例

在现有持久化技术的基础上将 SDO 和 DAS 结合使用,除了 SOA 的好处之外,其业务价值何在呢?请考虑以下管理方面的特征:

  • SDO 是一项开放标准。由于 SDO 是一项公开的标准,因此不会出现不得不选用某个供应商的情况。截至本文发布时,BEA、IBM、Versant、Versata 和 XCalia 均推出了 SDO 实现。同样,也已计划对 SDO 的数据访问进行标准化。

  • SDO 和 DAS 可以减少业务所必须维护的代码量。数据访问服务提供了一种标准的方法,用于保存封装在 SDO 中的信息,而不受后端系统的影响(不管此后端系统是使用 JDBC 访问的关系数据库、使用视图 Bean 访问的 LDAP 服务器或是具有 DAS 实现的其他后端系统)。实际上,为了使用异构后端系统而编写的自定义代码与数据访问服务采用标准的方式进行了整合。需要维护的代码较少,通常可以尽可能减少潜在的缺陷,从而缩短投入市场的时间和减少风险。

  • 将 SDO 和 DAS 结合使用,不需要受具体的持久化技术限制。DAS 不仅使应用程序无需依赖于数据库或操作系统,而且还使应用程序独立于整个持久化技术。通过使用多个数据访问服务,应用程序可以支持这些中介的基础持久化机制,而不用更改业务逻辑或呈现逻辑。对于 IT 环境复杂的组织,这样可以减少成本、整合资产,并可以减少将来进行高成本技术更改的风险。

  • 使用 SDO 和 DAS 有得有失。这两项均是新兴技术,尚处于早期发布阶段。很多数据访问服务可能不支持其他持久化技术的最先进功能(除非 DAS 专门为支持该技术而构建)。例如,IBM 的 JDBC Data Access Service 就尚不支持 SDO 表群集环境的分布式缓存。另外,若要充分发挥 SDO 和 DAS 的潜力,可能需要对各种新技术有所了解,包括 Web 服务、XPath 及 SDO 规范。对于开发组织,可以需要进行培训。







按部就班,使用 JDBC Data Access Service

本文剩下的部分将给出一个实例应用程序的实现。就功能而言,CloseOrderApplication 将使用 Rational Application Developer V6 包含的 JDBC DAS 关闭客户的订单。该应用程序将从数据库检索一个 SDO 对象图,对其进行更小,然后保存更改。将数据库架构映射到 SDO 对象图的元数据是使用 XML 编写的。

JDBC DAS 编程模型

图 7 所示的关系图演示了使用 JDBC Data Access Service 开发应用程序时应该有用的编程模型。


图 7. JDBC DAS 编程模型
图 7. JDBC DAS 编程模型
关于示例应用程序
此示例不仅是试验性的代码,因为其中实现了 JavaEE 最佳实践和实际错误处理。如果确实需要利用 JDBC Data Access Service 的代码(通常不过寥寥几行而已),清单 1 和清单 6 无疑是最为相关的了。数据库设置、JavaEE 数据源定义、XML 元数据的 JNDI 查询以及异常处理均属于 JavaEE 开发期间要做的工作,而不属于 SDO JDBC DAS。

在此模型中,JDBC DAS 使用 ConnectionWrapper 对 JDBC Connection 加以包装,以连接到数据存储区。使用 MetadataFactory 创建了 Metadata 的实例。然后使用各种构造(如 Tables、Columns 及 Relationships)定义元数据。数据库查询的等效项在元数据中定义为筛选器。不过,在此示例中,元数据、表、列、关系和筛选器均在元数据中定义,且在 XML 映射文档需要时透明地创建。(请参阅参考资料,以了解如何如上所示,在运行时使用元数据 API。)定义了元数据后,就会将其与 ConnectionWrapper 一起使用,以创建 JDBCAccess。中介可以获取和保存 SDO DataObject 图。

我们将通过执行以下任务来实现此实例应用程序:

  1. 创建 JaveEE 项目
  2. 设置数据库
  3. 定义 XML 元数据
  4. 创建方法
  5. 创建 JDBC 连接包装类
  6. 创建 JDBC 中介
  7. 从数据库检索 SDO DataObject 图
  8. 保存 SDO 图
  9. 关闭连接
  10. 检查应用程序异常
  11. 使用 Servlet 测试应用程序

示例应用程序的先决条件

此示例假设为 SDO DAS 使用 JavaEE 环境。不过并不需要应用程序服务器。IBM JDBC DAS 可以用于任何支持 Java SE 1.3 或更高版本的应用程序中。

1. 创建 JavaEE 项目

在 Rational Application Developer 的 J2EE Perspective 中:

  1. 选择 File => New => Enterprise Application Project。将其命名为 CloseOrder,然后选择 Finish

  2. 右键单击 CloseOrder,选择 New => Dynamic Web Project,将其命名为 CloseOrderWeb,然后单击 Finish

2. 设置数据库

图 8 显示了示例应用程序的数据库架构。其中包含一个 customer 条目和一个指向 order 条目的外键:


图 8. 数据库架构
图 8. 数据库架构

请注意,此处假设管理用户名和密码均为 db2admin

  1. 启动 DB2 命令行处理程序。缺省情况下,可以采用以下方式启动此工具:

    • Linux® 或 UNIX®:
      • 作为数据库管理员登录(比如 su db2admin
      • 键入 db2 并按 Enter
    • Windows®:
      • 选择 Start => All Programs => IBM DB2 => Command Line Tools => Command Line Processor
  2. 使用命令行处理程序执行以下代码:


    清单 1. DB2 命令
    																
    																								
    db2 => CREATE DATABASE EXAMPLE
    db2 => CONNECT TO EXAMPLE USER db2admin USING db2admin
    db2 => CREATE TABLE CUSTOMER(CUST_ID INTEGER NOT NULL, NAME VARCHAR(250), ORDER_ID INTEGER)
    db2 => ALTER TABLE CUSTOMER PRIMARY KEY(CUST_ID)
    db2 => CREATE TABLE ORDER(ORDER_ID INTEGER NOT NULL, STATUS VARCHAR(250), TOTAL INTEGER, CUSTOMER_ID INTEGER)
    db2 => ALTER TABLE ORDER PRIMARY KEY(ORDER_ID)
    db2 => INSERT INTO CUSTOMER(NAME, CUST_ID, ORDER_ID) VALUES ('Roland Barcia', 1, 2)
    db2 => INSERT INTO CUSTOMER(NAME, CUST_ID, ORDER_ID) VALUES ('Geoffrey Hambrick', 2, 1)
    db2 => INSERT INTO ORDER(ORDER_ID, STATUS, TOTAL, CUSTOMER_ID) VALUES (1, 'OPEN', 88, 1)
    db2 => INSERT INTO ORDER(ORDER_ID, STATUS, TOTAL, CUSTOMER_ID) VALUES (2, 'OPEN', 188, 5)
    db2 => ALTER TABLE CUSTOMER FOREIGN KEY(ORDER_ID) REFERENCES ORDER(ORDER_ID)
    
    																
    														

  3. CloseOrder 示例应用程序对 JDBC 数据库使用 JNDI 上下文引用,以避免硬编码数据库连接信息。展开 CloseOrderWeb,并双击 Deployment Descriptor: CloseOrderWeb

  4. 选择 Reference 选项卡,选择 Add... => Resourse reference,然后输入或选择字段值,如图 9 中所示。


    图 9. 数据源 JNDI 上下文引用
    图 9. 数据源 JNDI 上下文引用
  5. JNDI name 字段输入 jdbc/db2/Example,如图 10 中所示。


    图 10. 数据库 JNDI 名称
    图 10. 数据库 JNDI 名称

3. 定义 XML 元数据

若要将数据架构映射到 SDO 数据图,则必须定义中介元数据。


图 11. O/R 映射
图 11. O/R 映射

可以在运行时使用 com.ibm.websphere.sdo.mediator.jdbc.metadata.Metadata 定义元数据,图 7 对此作了简单描述(请参阅参考资料,以获得关于在运行时定义元数据的文档)。不过,我们的示例在 XML 中定义元数据。示例应用程序将元数据 XML 文件添加到类路径中,从而简化打开指向该文件的 java.io.InputStream 的过程,如要求创建中介时。

  1. 在 Rational Application Developer 中,右键单击 CloseOrderWeb 项目,然后选择 New => Source Folder

  2. 输入 xml 作为文件夹名称,然后选择 Finish

  3. 右键单击 CloseOrderWeb,然后选择 Java Resources => metadata,再选择 New => other... => Simple => Folder => Next

  4. 将文件夹命名为 DAS 并选择 Finish

  5. 右键单击 DAS 文件夹,然后采用类似的方式创建一个名为 metadata.xml 的新文件。

  6. 插入以下语句作为其内容:


    清单 2. 将元数据添加到 XML
    																
    																								
    <?xml version="1.0" encoding="ASCII" ?>
    <Metadata rootTable="CUSTOMER" xmlns:="http:///com/ibm/websphere/wdo/mediator/rdb/metadata.ecore" >
    	
    	<tables name="CUSTOMER">
    		<columns name="CUST_ID" type="int" />
    		<columns name="NAME" type="string" />
    		<columns name="ORDER_ID" type="int" />
    		<primaryKey columns="CUST_ID" />
    		<foreignKeys columns="ORDER_ID" />
    		<queryInfo filter="( CUST_ID = ? )">
    			<filterArguments name="CUST_ID" type="int" />
    		</queryInfo>
    	</tables>
    
    	<orderBys column="CUSTOMER.NAME" /> 
    	
    	<tables name="ORDER">
    		<columns name="ORDER_ID" type="int" />
    		<columns name="STATUS" type="string" />
    		<columns name="TOTAL" type="int" />
    		<primaryKey columns="ORDER_ID" />
    	</tables>
    	
    	<relationships name="OWNER" oppositeName="ORDER_RELATION" childKey="CUSTOMER" 
    		parentKey="ORDER" exclusive="false" />
    
    </Metadata>
    																
    														

    列和主键的 O/R 映射应当较为直观。请考虑以下对某些其他元数据标记的描述:

    • <tables rootTable="CUSTOMER">
      SDO 数据对象图必须定义访问的根入口点。在此应用程序中 customer 就是根对象。

    • <queryInfo>
      此标记定义筛选器。如果未定义筛选器,元数据将仍然有效;此时中介会将所有的客户(以及所有相关订单)作为 SDO 数据对象图返回。此处定义的筛选器将 SDO 图的返回缩小,使其仅包含与 filterArgument 匹配的客户。当中介从数据库检索此 SDO 图时,将要求传入一个名为 CUST_ID 的 int 类型参数。请注意,该参数并没有设置 name = "CUST_ID",因为其可能与数据库列名称不同。

    • <relationships>
      此标记定义 CUSTOMER.OPEN_ORDER_ID 的外键关系。在此关系中,customer 是子项,而 order 为父项。"Exclusive" 设置为 false,以指示中介检索所有相关订单,甚至包括没有 customer 引用的 order。如果将其设置为 true,则仅检索至少有一个子 customer 引用的 order 项。

    (如果收到验证错误“Element or attribute do not match QName”,可以将其忽略。本文是入门级的文章,将不在 Rational Application Developer 内设置验证。)

  7. 示例应用程序使用 JNDI 上下文引用查询元数据文件的位置。这样,应用程序就可以避免对文件名称进行硬编码了。展开 CloseOrderWeb,然后双击 Deployment Descriptor: CloseOrderWeb

  8. 选择 Reference 选项卡,然后选择 Add... => Resourse reference,并按照图 12 所示填写值。


    图 12. 元数据资源环境引用
    图 12. 元数据资源环境引用
  9. 在 JNDI name 字段中输入 cell/persistent/string/CloseOrderMetadata,如图 13 所示。


    图 13. 元数据 JNDI 名称
    图 13. 元数据 JNDI 名称

4. 创建方法

现在已经准备好,可以开始开发应用程序的代码了。

  1. 右键单击 CloseOrderWeb 项目,并选择 New => Class

  2. 在 package 中输入 developerworks.sdo.example 并将其命名为 CloseOrderApplication

为了更好地描述该应用程序,将在接下来的每一步对 CloseOrderApplication 类的各个方法单独进行讨论。首先是该类的唯一公共方法 closeOrder(),该方法负责整个示例应用程序的组织(图 14)。


图 14. CloseOrder 示例应用程序的事件序列
图 14. CloseOrder 示例应用程序的事件序列

以下方法是应用程序的入口点,图 14 显示的每个步骤几乎都由其进行组织:


清单 3. closeOrder 方法
												
																		
public void closeOrder(int customerId) {
    ConnectionWrapper conn =
        getConnectionWorker("java:comp/env/jdbc/DASDefault "); [1]
    JDBCAccess mediator = 
        createAccessWorker("java:comp/env/DAS/XMLMetadata ", conn); [2]

    DataObject order = null;
    try {
        order = getOpenOrderWorker(customerId, mediator); [3]
    } catch (NoCustomer nc) {
        Logger.warn("CloseOrder app could not find specified customer. [4]
            Prompting end user to create one or cancel transaction.", nc);
        // ... code to notify presentation layer would go here ...
    } catch (OrderNotOpen ono) {
        Logger.warn("CloseOrder app could not find order associated with 
            given customer. Notifying end user.", ono); [5]
        // ... same as above ...
    }

    order.set("STATUS", "CLOSED"); [6]
    persistChangesWorker(order, mediator); [7]
    closeConnectionWorker(conn); [8]
}

												
										

此方法的主要任务是:

  1. 获取 JDBC 连接包装类。
    getConnectionWorker() 代码详细说明数据库如何连接。辅助方法需要 JDBC 的 JNDI 上下文引用。

  2. 创建访问。
    辅助方法需要 ConnectionWrapper 和对 metadata.xml 的 JNDI 上下文引用。

  3. 获取客户的开放订单。
    辅助方法使用中介获取 SDO 对象图,遍历到与根 customer 项相关的 order,然后将其返回。

  4. 处理无客户的异常情况。
    获取开放订单的辅助方法可能引发 NoCustomer 异常。除了记录此情况并通知表示层之外(使用 closeOrder() 进行),典型的异常处理还可能包括使用新连接重试,或尝试采用名称替代 ID 进行查找。

  5. 处理无开放订单的异常情况。
    获取开放订单的辅助方法可能引发 OrderNotOpen 异常。对此的恰当异常处理由读者自行完成。

  6. 关闭订单。
    修改 order SDO DataObject 的状态字符串。

  7. 保存订单。
    将 order SDO DataObject 保存到数据库。

  8. 关闭连接。
    关闭连接。

5. 创建 JDBC 连接包装类

以下代码示例包含创建数据库连接的辅助方法。此方法完成了图 14 所示序列的步骤 (A) 和 (B) 的工作。


清单 4. getConnectionWorker 方法
												
																		
private ConnectionWrapper getConnectionWorker(String ctxRef) {
    Connection conn = null;
    try {
        InitialContext ctx = new InitialContext();
        DataSource ds = (DataSource) ctx.lookup(ctxRef);
        conn = ds.getConnection();
        conn.setAutoCommit(false);
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
        return ConnectionWrapperFactoryImpl.soleInstance.createConnectionWrapper(conn);
    } catch (NamingException ne) {
        throw new CloseOrderRuntime("CloseOrder could not lookup jdbc string
            binding: "+ctxRef, ne);
    } catch (SQLException sqle) {
        throw new
            CloseOrderRuntime("CloseOrder failed to make database connection", sqle);
    }
}

												
										

此方法的内容对于具有 JDBC 经验的 JavaEE 开发人员非常简单。唯一特定于 JDBC DAS 代码是从 ConnectionWrapperFactory 创建 ConnectionWrapper。请注意,此处使用了一个泛型运行时异常重新引发假定将由 JavaEE 应用程序中更高层处理的异常。

6. 创建 JDBC 中介

以下代码示例包含创建中介的辅助方法。此方法完成了图 14 所示序列的步骤 (C) 和 (D) 的工作。


清单 5. createAccessWorker 方法
												
																		
private JDBCAccess createAccessWorker(String ctxRef, ConnectionWrapper conn) {
    JDBCAccess mediator = null;
    String xmlPath = null;
    try {
        InitialContext ctx = new InitialContext();
        xmlPath = (String) ctx.lookup(ctxRef); <b>[1]</b>
        InputStream is = getClass().getClassLoader().getResourceAsStream(xmlPath); <b>[2]</b>
        mediator = JDBCAccessFactory.soleInstance.createAccess(is, conn); <b>[3]</b>
    } catch (NamingException ne) { <b>[4]</b>
        throw new CloseOrderRuntime("CloseOrder could not lookup metadata string 
            binding: "+ctxRef, ne);
    } catch (FileNotFoundException fnfe) {
        throw new CloseOrderRuntime("CloseOrder app cannot find: "+xmlPath, fnfe);
    } catch (IOException ioe) {
        throw new CloseOrderRuntime("CloseOrder app has filesystem error", ioe);
    } catch (AccessException me) {
        throw new CloseOrderRuntime("Metadata inside "+xmlPath+" is invalid.", me);
    }   
    return mediator;
}

												
										

此方法的主要任务是:

  1. 使用 JNDI 上下文引用获取文件名。
    采用与查询 JDBC 数据源类似的方法检索 XML 元数据文件名。

  2. 创建文件流
    使用文件名创建指向 XML 元数据文件的常规 java.io.InputStream。

  3. 创建 JDBC 访问。
    使用 JDBCAccessFactory,并将文件流和数据库连接包装类作为参数,以创建中介。

  4. 处理异常。
    此处也是使用一个泛型运行时异常处理各种异常。

7. 从数据库检索 SDO DataObject 图

以下代码片段包含了从数据库检索 SDO 对象图并返回客户的开放订单的辅助方法。此方法完成图 14 所示序列中的步骤 (E) 的工作。


清单 6. getOpenOrderWorker 方法
												
																		
private DataObject getOpenOrderWorker(int customerId, JDBCAccess mediator) throws NoCustomer, OrderNotOpen {
    DataObject graph = null;
    try {
        DataObject param = mediator.getParameterDataObject();
        param.setInt("CUST_ID", customerId); [1]
        graph = mediator.getGraph(param); [2]
    }
    catch(AccessException me) {
        throw new CloseOrderRuntime("CloseOrder app failed to get customer graph from 
            mediator. CUST_ID="+customerId, me);
    }
    
    List cList = graph.getList("CUSTOMER"); [3]
    if(cList.size() == 0) {
        throw new NoCustomer("CloseOrder app could not find customer for 
            CUST_ID="+customerId);
    }
    DataObject customer = graph.getDataObject("CUSTOMER.0"); [4]
    
    if(customer.getInt("ORDER_ID") == 0 || graph.getList("ORDER").size() != 1) {
        throw new OrderNotOpen("CloseOrder app did not find an open [5]
            order for customer with CUST_ID="+customerId);
    }
    
    return customer.getDataObject("ORDER_RELATION"); [6]
}

												
										

此方法的主要任务是:

  1. 创建参数。
    创建一个名为 CUST_ID 的参数,并将其设置为 customerId。此参数在筛选器中使用,以将 SDO 图限制为仅包含具有元数据 XML 中指定的特定 ID 的客户。

  2. 获取 SDO DataObject 图。
    使用步骤 1 中构造的参数对中介调用 getGraph 方法。此图中应包含客户及其相关订单。

  3. 检查客户是否存在。
    getList("CUSTOMER") 方法返回 SDO 图中所有客户数据对象的列表。如果大小为零,则将引发 NoCustomer 应用程序异常。

  4. 获取客户。
    从 SDO 图获取客户。请注意,追加到 CUSTOMER.0 的零是必需的,用以指示要检索 customer 列表的哪个元素(在此例中,列表中仅有一个客户)。

  5. 检查是否存在开放订单。
    如果订单不是开放状态,则不能对其进行关闭操作。将检查 OPEN_ORDER_ID 外键,还将检查 order DataObject 列表是否为非零。

  6. 返回开放订单。
    通过遍历元数据中定义的关系,从 customer 子图检索开放订单。

8. 保存 SDO 图

以下代码示例包含保存已更新 SDO DataObject 图的辅助方法。此方法完成了图 14 所示序列的步骤 (G) 的工作。


清单 7. persistChangeWorker method
												
																		
private void persistChangesWorker(DataObject graph, JDBCAccess mediator) {
    try {
        mediator.applyChanges(graph);
    } catch(AccessException me) {
        throw new CloseOrderRuntime("CloseOrder app failed to persist SDO graph.              
            Access="+mediator+"\nGraph="+graph, me);
    }
}

												
										

9. 关闭连接

以下代码示例包含关闭数据库连接的辅助方法。此代码完成了图 14 所示序列的步骤 (H) 的工作。


清单 8. closeConnectionWorker 方法
												
																		
private static void closeConnectionWorker(ConnectionWrapper conn) {
    try {
        conn.getConnection().close();
    } catch (SQLException sqle) {
        throw new CloseOrderRuntime("CloseOrder app failed to close 
            ConnectionWrapper="+conn, sqle);
    }
}

												
										

10. 检查应用程序异常

CloseOrderApplication 使用了以下异常,这些异常都位于 developerworks.sdo.example.exception 包内:


清单 9. CloseOrderApplication 所使用的异常
												
																		
public class CloseOrderRuntime extends RuntimeException {
    public CloseOrderRuntime() {
        super();
    }
    public CloseOrderRuntime(String msg) {
        super(msg);
    }
    public CloseOrderRuntime(Exception nested) {
        super(nested);
    }
    public CloseOrderRuntime(String msg, Exception nested) {
        super(msg, nested);
    }
}

public class NoCustomer extends Exception {
    public NoCustomer() {
        super();
    } 
    public NoCustomer(String msg) {
        super(msg);
    }
}

public class OrderNotOpen extends Exception {
    public OrderNotOpen() {
        super();
    }
    public OrderNotOpen(String msg) {
        super(msg);
    }
}

												
										

11. 使用 Servlet 测试应用程序

  1. 右键单击 Deployment Descriptor: CloseOrderWeb 项目,然后选择 New => Servlet...

  2. 在 Name 字段输入 TestCloseOrder,然后单击 Next

  3. 在 Java package 中输入 developerworks.sdo.example.test,然后单击 Finish

  4. 插入以下代码作为 doGet 方法的内容:


    清单 10. 测试 Servlet
    																
    																								
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws 
        ServletException, IOException {
    	String customerId = request.getParameter("customerId");
    	CloseOrderApplication coa = new CloseOrderApplication();
    	coa.closeOrder(Integer.parseInt(customerId));
    	response.getWriter().print("Close order request processed successfully.");
    }
    																
    														

  5. 选择 Servers 选项卡,右键单击 WebSphere Application Server v6.0,然后选择 Start

  6. 再次右键单击服务器,并选择 Add and remove projects...,以将 CloseOrder EAR 项目部署到服务器。

  7. 部署了项目之后,使用以下 URL 在 Web 浏览器中打开管理控制台:http://localhost:9060/admin。

  8. 选择 Log in => Security => Global security => JAAS Configuration => J2C Authentication data => New,并按照图 15 所示填写表单。


    图 15. 数据库身份验证入口
    图 15. 数据库身份验证入口
  9. 选择 OK,然后选择 Save

  10. 选择 Environment => WebSphere Variables => DB2UNIVERSAL_JDBC_DRIVER_PATH 并输入您的 DB2 驱动程序目录。Windows 下的缺省值为 C:\Program Files\IBM\SQLLIB\java

  11. 选择 Resources => JDBC Providers => New 并按照图 16 所示填写表单。


    图 16. JDBC Provider 配置
    DB2-Provider.PNG
  12. 依次单击 NextOKSave

  13. 选择 DB2 Universal JDBC Driver Provider (XA) => Data sources => New

  14. 插入 jdbc/db2/Example 作为 JNDI name。

  15. 选择 DB2 Login 作为 Component-managed authentication alias。

  16. 输入 EXAMPLE 作为 Database name。

  17. 输入 localhost(或 DB2 的主机)作为 Server name,然后单击 Save

  18. 为了确保数据源正常工作,请选择 DB2 Universal JDBC Driver XA DataSource 旁边的框,并单击 Test connection

  19. 最后一个管理步骤就是 metadata.xml 文件的 JNDI 字符串绑定。选择 Environment => Naming => Name Space Bindings => New => String => Next 并按照图 17 所示填写表单。Name Space value 中的 Name 为 string/CloseOrderApp/metadata


    图 17. XML 文件名字符串绑定
    图 17. XML 文件名字符串绑定
  20. 选择 Next => FinishSave

  21. 重新启动服务器,以确保所有 JNDI 绑定均已更新。

  22. 若要运行该应用程序,请将以下 URL 输入到 Web 浏览器中:http://localhost:9080/CloseOrderWeb/TestCloseOrder?customerId=2







结束语

JDBC Data Access Service 提供了对面向服务的体系结构的持久化层的标准化访问。本文演示了 SDO DAS 如何如何适应大型的企业部署,以及如何使用简洁且用户友好的 XML 元数据将现有数据库架构映射到 SDO。

posted on 2006-04-17 02:33 wsdfsdf 阅读(424) 评论(0)  编辑 收藏 引用 所属分类: 技术文章


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理