IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management | WebSphere  >

在 WebSphere Federation Server V9.1 中使用联邦过程

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 中级

Hans Zeller (hzeller@us.ibm.com), 高级技术人员, IBM Silicon Valley Lab
Qinglong (Peter) Hu (qhu@us.ibm.com), 顾问软件工程师, IBM Silicon Valley Lab
Dimple Bhatia (dimple@us.ibm.com), 高级软件工程师, IBM Silicon Valley Lab

2006 年 12 月 18 日

学习在 WebSphere® Federation Server 中何时、何处 以及如何使用联邦过程。本文从应用程序开发人员的视角描述这个新特性。描述如何创建和调用联邦过程,以及如何诊断和避免某些最常见的问题。

简介

WebSphere Federation Server(以前称为 WebSphere Information Integrator)使用 “昵称” 对远程数据源上的数据集进行联邦访问。昵称作为远程表或类似于表的数据集的本地代理。参考资料 小节中提供了介绍性文章的链接,可以帮助读者熟悉联邦概念,比如服务器、包装器和昵称。

联邦过程与昵称的相似之处是它们允许访问远程存储过程。它们似乎应该被称为 “存储过程昵称”;但是,因为昵称被看作具有表性质的对象,而不是过程,所以不这么称呼。在大多数情况下,创建和调用联邦过程是一个非常简单的过程。例如,假设希望调用远程存储过程 rem_proc 而且已经有一个服务器 s。以下两个 SQL 语句创建一个联邦过程 my_fed_proc 并用一个输入参数和一个输出参数调用它:

CREATE PROCEDURE my_fed_proc  SOURCE rem_schema.rem_proc  FOR SERVER s

CALL my_fed_proc(3,?)

当然,联邦过程不只是如此,以下各节会为更高级的使用场景提供有用的信息:





回页首


为什么使用联邦过程?

存储过程的好处

存储过程是为了解决分布式计算的问题而发明的。它们允许客户机通过只发送一个消息在数据库服务器上执行多个操作。还有一些重要的副作用:它们允许 DBA 对业务逻辑进行封装、确保数据一致性以及促进代码重用。在许多情况下,这些副作用是使用存储过程的主要原因。换句话说,存储过程提供以下关键好处:

  • 性能 —— 存储过程的性能提高主要来自于减少客户机(常常在远程计算机上)和数据库服务器之间发送的消息数量。因此,这些提高常常在过程中有多个 SQL 语句时表现出来。
  • 封装 —— 存储过程是实现最低的业务逻辑层的好方法。
  • 安全性 —— 因为 SQL 允许控制表、视图和过程等对象,DBA 可以通过禁止直接访问底层表并迫使客户机使用过程来执行特定的业务事务,从而将业务逻辑封装起来。这样就更容易确保安全性和数据一致性。
  • SQL 语义 —— 常规的 SQL 操作和存储过程调用共享同一个客户机库以及 SQL 接口的事务、错误和安全模型。无论是与对 SQL 表的访问一起使用,还是单独使用,这都可以大大简化应用程序开发。

从存储过程到联邦过程

到目前为止,本文讨论的都是存储过程。如果只需要用您熟悉的 SQL 方言访问来自一个数据源的表和过程,那么实际上不需要联邦过程。但是,存储过程和其他 SQL 对象常常存在于不同的数据源上,而且可能需要使用不同的 SQL 方言。这会使应用程序变得非常复杂。为了解决这个问题,WebSphere Federation Server V9.1 中出现了一个新特性:联邦过程。联邦过程结合了上面讨论的存储过程优点和下面这些联邦优点:

  • 位置无关性 —— 应用程序不需要知道各个对象的位置,可以在单一数据库连接、单一事务甚至单一 SQL 语句中使用来自多个数据源的对象(昵称、过程)。
  • 透明性 —— 调用联邦过程与调用本地 DB2 过程相似,都通过 DB2 客户机接口使用共同的 SQL 方言和数据类型集合,而且采用同样的方式来处理结果集。DB2 模型包括数据库连接,它提供了分布式事务而且避免了对每个过程调用进行身份验证。
  • 异构性 —— 联邦过程可以调用不同数据源上的过程。在当前版本中,选择的范围只限于 Sybase 和 Oracle 过程(本文的 限制 一节中将详细讨论当前的限制)。在许多情况下,联邦服务器需要处理这些数据源实现的差异。这对于结果集的处理尤其重要,因为结果集的处理在不同数据源上有本质差异。
  • 自治性 —— 联邦过程不需要在数据源上进行设置、安装或定制。可以按原样使用数据源上的现有过程。

联邦过程真的是必要的吗?

上面讨论的是联邦过程的好处。本节考查一些替代方案,讨论它们如何适应其他环境,比如 Web 服务。假设一个应用程序需要在一个工作单元中调用不同数据源上的两个存储过程。我们根据应用程序是否具有以下情况来比较几个场景:

  1. 使用客户机库。
  2. 管理分布式事务。
  3. 管理分布式安全性。
  4. 了解不同数据源上对象的位置。
  5. 了解语义和数据类型方面的差异。

第一个选项是使用数据库客户机(比如 Java Database Connectivity[JDBC])来直接访问每个数据源,而不使用联邦过程。尽管对于简单的应用程序这是非常有用的方法,但是应用程序需要自己处理上面提到的 5 个方面。对于 DB2 以及 WebSphere Federation Server,客户机接口的选择范围包括嵌入式 SQL(不支持存储过程的结果集)、CLI、Distributed Relational Database Architecture(DRDA)、Open Database Connectivity(ODBC)、JDBC 和 Structured Query Language for Java(SQLJ)。这些接口不允许 SQL 查询或存储过程同时使用多个数据源上的对象。图 1 给出一个这样的分布式应用程序:


图 1. 使用客户机接口的简单应用程序
通过客户机接口直接访问数据源的应用程序

应用程序设计人员可能不希望使用数据库客户机接口。为了解决这个问题,可以使用每个数据源的 Web 服务提供者。现在,应用程序不再需要使用数据库客户机库,但是仍然需要管理 上面列表 中的所有其他方面。


图 2. 使用 Web 服务的应用程序
通过 Web 服务访问数据源的应用程序

如果希望自动管理刚才提到的那些方面,可以使用联邦服务器并将所有这些方面虚拟化成一个 SQL 接口。本文的其余部分将详细讨论这种方法。利用联邦方法,就不再需要在应用程序中管理 上面列表 中的项目,但是第一项除外。


图 3. 联邦应用程序
通过联邦访问数据源的应用程序

如果应用程序使用 Web 服务接口而不是 SQL 客户机库,那么它可以结合 Web 服务和联邦概念的优点,通过 Web 服务访问联邦服务器,见 图 4


图 4. 利用 Web 服务提供者的联邦应用程序
使用 Web 服务提供者访问联邦数据源的应用程序

现在,应用程序不再需要管理上面列出的任何项目了。当然,Web 服务提供的好处不只是避免使用客户机库。这种方式的其他变体包括使用联邦服务器中的 Web 服务包装器。正如前面提到的,本文的其余部分主要关注 图 3 中的配置。





回页首


限制

在设计应用程序之前,应用程序设计人员需要了解在使用联邦过程时的一些限制。这些限制的一部分应用于 DB2 过程或应用于联邦,一些限制是联邦过程所特有的:

数据源:

  • 当前,只在以下数据源上支持联邦过程:
    • Oracle
    • Sybase

fenced 包装器支持:

  • 联邦过程不支持 fenced 包装器。

调用联邦过程:

  • 从外部用户定义函数调用的联邦过程在联邦服务器上必须不具有访问级别 READS SQL DATA 或 MODIFIES SQL DATA(对联邦语句的一般性限制)。
  • 联邦过程只支持 CALL RESOLUTION IMMEDIATE(CALL RESOLUTION DEFERRED 绑定选项是 DB2 中已经废弃的特性)。
  • 在 Oracle 中,可以定义输出到缓冲区或标准输出的函数。对于在这种函数上定义的联邦过程,用户不应该期望看到输出(输出可能会出现在数据源上,也可能不出现)。

数据类型支持:

  • 联邦过程支持昵称所支持的所有数据类型,但是过程参数不能使用大对象(LOB)。

事务支持:

  • 在触发器、动态合成语句、标量、表、行函数和方法中不能调用具有访问级别 MODIFIES SQL DATA 的联邦过程。一旦发出 SAVEPOINT 语句,用户就不能调用具有访问级别 MODIFIES SQL DATA 的联邦过程(对联邦语句的一般性限制)。
  • 联邦过程所引用的远程过程不能发出 COMMIT 或 ROLLBACK 语句。因为不能强制实施这一限制,如果远程过程有 COMMIT 或 ROLLBACK 语句,就可能发生数据不一致(见下面的 CALL 语句的事务问题 一节)。

其他限制:

  • 不支持 ALTER PROCEDURE。
  • 对于 Sybase 服务器 12.0 版,所有参数都是 “输入” 参数。因此,对于 Sybase 12.0 版数据源,不能返回输出参数的值。这个限制对于更高的版本(比如 12.5 和 15)不存在(Sybase 12 编目限制)。

结果集:

  • 只返回一个结果集。如果远程过程返回多个结果集,那么其他结果集被丢弃。
  • 对于同时返回输出参数和结果集的 Sybase 过程,结果集被丢弃。
  • 返回结果集的 Sybase 过程总是返回 0 作为整数返回状态,实际的返回状态值被忽略。
  • 不支持 Sybase 游标参数。不允许在客户机操作中使用 Sybase 游标参数,因此不支持(Sybase 限制)。
  • 不支持 REFCURSOR 类型的 Oracle 输入参数(支持 REFCURSOR 类型的输出参数,并映射为结果集)。
  • 在远程过程上不支持可更新、可持有和可滚动的游标。如果远程过程定义了 WITH HOLD 和 SCROLLABLE 结果集,那么游标属性(WITH HOLD 和 SCROLLABLE)丢失,返回的结果集不是可持有或可滚动的,而且是只读的。可持有结果集允许应用程序在隐式或显式提交之后一直将游标打开着。可滚动结果集允许游标移动到结果集中的任意行。




回页首


联邦过程的外部调用

正如简介中提到的,联邦过程提供了位置透明性。在创建联邦过程之后,就可以像调用 DB2 过程那样调用它们。它们遵循 DB2 过程模型并提供一个同质的接口,可以将数据源中的许多特殊特性映射到 DB2。可以使用 CREATE PROCEDURE (Sourced) 语句创建联邦过程。在 简介 一节中,您已经看到了一个使用必要子句的 CREATE PROCEDURE (Sourced) 语句示例。这里讨论可选的子句以及 CREATE PROCEDURE (Sourced) 语句行为的更多细节。关于 CREATE PROCEDURE (Sourced) 语句的详细语法,请参考 参考资料 中的 DB2 Information Center 链接。CREATE PROCEDURE (Sourced) 语句提供下面这些功能:

  • 在 Oracle 函数上创建过程。

    返回值变成联邦过程的第一个参数。它是名为 “DEFAULT” 的输出参数。

  • 支持包中的 Oracle 过程。

    CREATE PROCEDURE 语句为包中的 Oracle 例程提供了特殊语法,即 SOURCE 子句中分三部分的名称,其中中间的部分标识包。

  • Oracle REFCURSOR 输出参数作为 DB2 结果集返回。

    注: NUMBER OF PARAMETERS 子句中考虑这些参数,但是它们不作为联邦过程的参数出现。

  • 在重载的数据源过程上创建过程。

    这可以用两种方式实现:

    • 如果两个或更多的数据源过程具有相同的模式和过程名,但是参数数量不同,那么可以在 CREATE PROCEDURE 语句中指定 NUMBER OF PARAMETERS。

      注: 这是远程过程的参数数量,包括 REFCURSOR 参数,但是不包括函数的返回值。创建的联邦过程可以具有不同数量的参数。

    • 如果多个数据源过程或函数具有同样的名称和参数数量,那么需要指定 UNIQUE ID。对于 Sybase 过程,这是不必要的(也不支持)。对于 Oracle 例程,UNIQUE ID 值是 ALL_ARGUMENTS.OVERLOAD 列的(字符)值,它惟一地标识这个例程。

  • 根据应用程序,声明返回给客户机/调用者的结果集。见下面的 结果集 一节。

  • 指定过程的访问级别、确定性、外部动作属性。

    因为联邦过程所引用的远程过程不由联邦服务器进行管理,所以当过程在数据源上执行时无法强制实施选择的级别。如果在用户指定的访问级别值与远程过程在数据源上实际采用的级别之间有差异,那么可能出现数据不一致。如果用户指定了这些选项,但是与数据源上的选项值有冲突,那么返回一个错误(SQL 1255N)。如果用户没有为这些选项指定任何值,那么使用数据源上的值。如果这些选项在数据源上不可用,那么默认值是 MODIFIES SQL DATA、NOT DETERMINISTIC 和 EXTERNAL ACTION。

结果集

存储过程可以返回零个或更多的结果集,每个结果集由一组行组成。一个结果集中的所有行具有相同的列数量和列类型,而不同的结果集可以具有不同的列布局。不同的数据源在如何实现结果集方面有显著的差异。

  • 在 DB2 中,所有结果集的生成不需要将它们声明为参数。有两种结果集,“RETURN TO CLIENT” 和 “RETURN TO CALLER”。前一种类型绕过所有嵌套的过程,直接返回给最初的应用程序;而后一种类型只能由调用者使用。调用者可以是客户机应用程序,也可以是另一个过程。
  • 一般的 Sybase 结果集不声明为参数,并具有与 DB2 中 “RETURN TO CLIENT” 结果集相似的语义。为了能够在调用者中使用结果集,Sybase 添加了游标参数,但是这种参数只能在 Sybase 服务器中使用,而不能从 Sybase 客户机接口(比如联邦)使用。
  • 在 Oracle 中,所有结果集显式地声明为 REFCURSOR 类型的参数。它们必须显式传递给调用者和被调用者。

    CREATE PROCEDURE 语句中的 WITH RETURN TO CALLER/CLIENT 子句帮助实现所需的 Sybase 和 Oracle 结果集行为。关于进一步的信息,请参考下面的 示例设计联邦过程期间的问题判断 两节。

联邦过程参数和结果集的数据类型

  • 在创建联邦过程时,使用默认的转发类型映射将远程过程参数和结果集的列的数据类型映射为 DB2 数据类型。
  • 对于 Oracle 中没有精度、刻度或长度的数据类型,Oracle 数据类型被映射为具有最大长度的字符串或者 DB2 中的 DOUBLE,以便在执行 CREATE PROCEDURE 期间获得最大的范围。
  • 用户可以使用 CREATE TYPE MAPPING 语句覆盖过程参数的默认类型映射。但是,结果集的类型映射不受用户定义的类型映射影响。

联邦过程编目

如果联邦过程的签名是未知的,那么用户可以使用下面列出的编目来查看签名。下面的 “示例” 一节描述了执行编目查看的查询。假设您知道联邦过程的名称和模式,SYSCAT.ROUTINEPARMS 是首先查询的编目。可以在 示例 一节中找到一些查询示例 。

  • SYSCAT.ROUTINESFEDERATED
    包含关于定义的联邦过程的信息,比如数据源名、远程过程名、远程模式名。
  • SYSCAT.ROUTINES —— 包含关于用户定义例程(UDB 表函数、标量函数和联邦过程)的信息。
  • SYSCAT.ROUTINEPARMS —— 包含关于 SYSCAT.ROUTINES 中定义的例程的例程参数信息。
  • SYSCAT.ROUTINEOPTIONS —— 包含关于联邦过程选项值的信息,比如数据源名、远程过程名、远程模式名和远程过程中的参数数量。在 Oracle 数据源的情况下,这个编目还包含 REFCURSOR 的数量。
  • SYSCAT.ROUTINEPARMOPTIONS —— 包含关于联邦过程参数选项值的信息,比如远程参数名和远程参数类型名。

调用联邦过程

使用 CALL 语句调用联邦过程。整数返回码映射为 GET DIAGNOSTICS 语句中的 DB2_RETURN_STATUS 变量。对于 Sybase,只在不返回结果集时接收整数返回码。所需的特权和用户映射与昵称所需的相似:

  • 用户在数据源上需要 EXECUTE 授权和有效的用户映射。即使在通过本地语句或过程间接调用联邦过程时,也需要如此。
  • 可以使用 GRANT/REVOKE (routine privileges) 语句授予联邦过程上的特权。

删除联邦过程

  • 可以使用 DROP 语句删除联邦过程。
  • 删除一个联邦过程会从本地编目中删除它,但是不会改变数据源上的编目。
  • 依赖于这个过程的包会失效。

使用 DROP 语句的示例见 示例 一节。

对联邦过程的工具支持

到目前为止,本文已经讨论了联邦过程的外部。现在,注意力转移到对这个特性的用户界面支持。有两个界面:

  • 控制中心 —— 控制中心提供以下功能:
    • 创建和删除联邦过程。
    • 授予和撤消联邦过程上的特权。
    • 根据远程模式名、远程包名和远程过程名来发现远程过程。
    • 手工指定远程过程的属性。
  • DB2 Workbench —— DB2 Workbench 工具允许执行用控制中心创建的过程。用户可以查看执行的状态、输出参数和结果集。




回页首


示例

您已经在 简介 一节中见到了一个简单的示例。以下示例演示如何处理重载的过程,以及如何在编目中查询本地属性。还演示如何在 CREATE PROCEDURE 语句中利用结果集语法。

股票经纪公司 XYZ 在 StockOptions 包中有以下 Oracle 存储过程:

  • 过程 StockInfo,输入参数是 char 类型的用户名;StockInfo (username IN char)。它返回一个结果集,其中包含用户的股票持有量信息。结果集的每一行包含两列:
    • 给定用户持有的一种股票的数量。
    • 此股票的名称。
    • 在 Oracle 上,这个结果集常常由过程的调用者使用。
  • 过程 StockInfo,输入参数是帐号;StockInfo (accountNum IN integer)。帐号被设计为一个整数。它返回一个结果集,其中记录:
    • 给定帐号中一种股票的数量。
    • 根据实时报价计算出的股票总市值。
    • 此股票的名称。
    • 当从 Oracle 中调用这个过程时,调用者常常将结果集传递给客户机。

这家股票经纪公司还定义了以下 Sybase 过程:

  • 过程 StockQuote,输入参数是股票名称和日期;StockQuote(stockName IN char, transDate IN DATE)。它以输出参数的形式返回给定股票在给定日期的报价。注意,因为 Sybase 过程允许用户为 OUT 参数传递初始值,所以 DB2 将 Sybase OUT 参数作为 INOUT 参数对待。根据编写过程的方式不同,可能需要指定输入值,也可能不需要。

DBA Bob 创建了:

  • 用于 Oracle 和 Sybase 的包装器。
  • 服务器定义:用于 Oracle 的 SORA 和用于 Sybase 的 SSYB。

然后,Bob 在远程 Oracle 和 Sybase 过程上创建联邦过程。因为两个 Oracle 过程具有相同的名称和参数数量,但是签名不同,所以 DBA 从 Oracle 系统编目中的 ALL_ARGUMENTS.OVERLOAD 列查询 UNIQUE ID。

对于以用户名作为输入参数的 Oracle 过程,创建的联邦过程 ORASTOCKINFO 如下:

CREATE PROCEDURE ORASTOCKINFO SOURCE BOB.STOCKOPTIONS.STOCKINFO
                              UNIQUE ID '2' FOR SERVER SORA 

对于以帐号作为输入参数的 Oracle 过程,创建的联邦过程 ORASTOCKVALUE 如下:

CREATE PROCEDURE ORASTOCKVALUE SOURCE BOB.STOCKOPTIONS.STOCKINFO
                               UNIQUE ID '3' FOR SERVER SORA
                               WITH RETURN TO CLIENT ALL

对于以股票名称和日期作为输入参数的远程 Sybase 过程,创建的联邦过程 SYBSTOCKQUOTE 如下:

CREATE PROCEDURE SYBSTOCKQUOTE SOURCE BOB.STOCKQUOTE FOR SERVER SSYB

用户可以使用 SYSCAT.ROUTINESFEDERATED 编目查找过程属性,比如例程模式、特定名称、参数数量、确定性、外部动作和访问级别。

可以使用以下查询查找 ORASTOCKINFO 和 ORASTOCKVALUE 过程的属性:

SELECT ROUTINESCHEMA, ROUTINENAME, PARM_COUNT, DETERMINISTIC,
       EXTERNAL_ACTION, SQL_DATA_ACCESS 
FROM   SYSCAT.ROUTINESFEDERATED 
WHERE  ROUTINENAME IN ('ORASTOCKINFO', 'ORASTOCKVALUE')

ROUTINESCHEMA  ROUTINENAME   PARM_COUNT DETERMINISTIC EXTERNAL_ACTION SQL_DATA_ACCESS
-------------  ------------- ---------- ------------- --------------- ---------------
BOB            ORASTOCKINFO  1          N             E               M
BOB            ORASTOCKVALUE 1          N             E               M

E = Procedure has external action

routineschema 是联邦过程的模式名,而不是数据源过程的模式名。

可以使用以下查询查找 SYBSTOCKQUOTE 过程的属性:

SELECT ROUTINESCHEMA, SPECIFICNAME, PARM_COUNT, DETERMINISTIC,
       EXTERNAL_ACTION, SQL_DATA_ACCESS 
FROM   SYSCAT.ROUTINESFEDERATED 
WHERE  ROUTINENAME = 'SYBSTOCKQUOTE'

ROUTINESCHEMA  SPECIFICNAME       PARM_COUNT DETERMINISTIC EXTERNAL_ACTION SQL_DATA_ACCESS
-------------  ------------------ ---------- ------------- --------------- ---------------
BOB            SQL060412112907000 2          N             E               M

可以使用 SYSCAT.ROUTINEPARMS 编目寻找参数信息,比如序数、参数名、参数模式和参数类型名。

可以使用以下查询查找 ORASTOCKINFO 和 ORASTOCKVALUE 过程的参数信息:

SELECT CHAR(ROUTINENAME,30) AS ROUTINENAME, ORDINAL, CHAR(PARMNAME,30) AS NAME,
       ROWTYPE, CHAR(TYPENAME,30) AS TYPE 
FROM   SYSCAT.ROUTINEPARMS 
WHERE  ROUTINENAME IN ('ORASTOCKINFO', 'ORASTOCKVALUE') AND ROUTINESCHEMA ='BOB'
ORDER  BY ROUTINENAME, ORDINAL;

ROUTINENAME    ORDINAL NAME            ROWTYPE    TYPE                          
-------------- ------- --------------- --------   -----------
ORASTOCKINFO         1 USERNAME        P          VARCHAR                      
ORASTOCKVALUE        1 ACCTNUM         P          DOUBLE
   
 P = Input Parameter

可以使用以下查询查找 SYBSTOCKQUOTE 过程的参数信息:

SELECT ORDINAL, CHAR(PARMNAME,30) AS NAME,ROWTYPE, 			     
       CHAR(TYPENAME,30) AS TYPE 
FROM   SYSCAT.ROUTINEPARMS 
WHERE  ROUTINENAME= 'SYBSTOCKQUOTE' AND ROUTINESCHEMA ='BOB'
ORDER  BY ORDINAL;

ORDINAL NAME            ROWTYPE    TYPE                          
------- --------------- --------   -----------
      1 STOCKNAME              P   CHAR  
      2 DATE                   P   TIMESTAMP
      3 STOCKVAL               B   DOUBLE                  
      
 P = Input Parameter
 O = Output Parameter
 B = InOut Parameter

现在假设有一个 UDB 过程 computeStockValue(),这个过程:

  • 以用户名和日期作为输入参数。
  • 调用用于 Oracle 的联邦过程 OraStockInfo()。
  • 对于从 OraStockInfo() 返回的每个股票名,调用联邦过程 SybStockQuote,传递股票名和日期。
  • 根据 SybStockQuote 过程返回的股票报价,用股票数量乘以股票报价计算出市值。

图 5. 调用 OraStockInfo() 和 SybStockQuote() 过程的 UDB 过程
调用 OraStockInfo() 和 SybStockQuote() 过程的 UDB 过程

假设还有另一个 UDB 过程 GetStockValue(),这个过程:

  • 以帐号作为输入参数。
  • 调用联邦过程 OraStockValue()。

因为 OraStockValue() 过程的结果集定义为返回给客户机,所以这个 UDB 过程无法访问它,给定帐号的股票市值直接返回给调用 UDB 过程的应用程序。


图 6. 调用 OraStockValue() 的 UDB 过程 GetStockValue()
调用 OraStockValue() 的 UDB 过程 GetStockValue()

如果用户希望删除刚才创建的联邦过程,可以使用 DROP 语句。

在这个例子中,因为过程没有重载,可以使用过程名来删除 ORASTOCKINFO 过程。

DROP PROCEDURE ORASTOCKINFO

如果还有另一个过程也称为 ORASTOCKINFO,但是参数数量不同,那么可以使用过程签名或特定名来删除过程。因此 DROP 语句可以是:

DROP PROCEDURE ORASTOCKINFO(VARCHAR(10))

DROP SPECIFIC PROCEDURE SQL060412112756100





回页首


设计联邦过程期间的问题判断

在设计应用程序时,有一些常见问题需要注意。对于在设计联邦过程时可能遇到的问题,本节讨论一些故障排除方面的技巧。

对于错误消息 SQL1822N,从远程数据源接收到的错误消息内容常常被截断。可以在 db2diag.log 文件中找到完整的错误消息。例如,

call fstp(20)
SQL1822N  Unexpected error code "6550" received from data source "SERV". 
Associated text and tokens are "ORA-06550: line 1, column 7: PLS-00201: 
identifier 'J15USER1".  SQLSTATE=560BD

如果远程 Oracle 过程被删除,那么抛出以上错误。db2diag.log 包含完整的错误消息:

db2diag -filter 'function:=error_report'

2006-04-24-16.56.44.033504-420 E928575A670        LEVEL: Error
PID     : 7000234              TID  : 1           PROC : db2agent (FSPDB)
INSTANCE: phu                  NODE : 000         DB   : FSPDB
APPHDL  : 0-7                  APPID: *LOCAL.phu.060424235433
AUTHID  : NEWTON
FUNCTION: DB2 UDB, net8 wrapper, Net8_Statement::error_report, probe:10
DATA #1 : String, 28 bytes
Oracle Error - Current User
DATA #2 : String with size, 6 bytes
NEWTON
DATA #3 : String, 22 bytes
Oracle Error Received
DATA #4 : String, 142 bytes
ORA-06550: line 1, column 7:
PLS-00201: identifier 'J15USER1.ORA_STP' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

创建联邦过程

如果在执行 CREATE PROCEDURE 语句期间抛出错误 SQL1253N(在数据源上没有找到 CREATE PROCEDURE (Sourced) 语句中指定的源过程),那么可以对远程编目表发出以下查询,以检查远程过程信息。

对于包中的 Oracle 过程,按 passthru 模式对 Oracle 服务器使用以下查询:

select owner, package_name, object_name, overload, parm_count
from   (
         select owner, package_name, object_name, overload,
                sum(case when data_type is null then 0 else 1 end) as parm_count 
         from sys.all_arguments 
         where data_level = 0
         group by owner, package_name, object_name, overload
       ) aa
where  object_name = '<remote_proc_name>' and
       package_name = '<remote_package>' and
       owner = '<remote_schema>' and
       overload = '<unique_id>' and   -- optional
       parm_count = <num_of_parameters> -- optional

对于包外的 Oracle 过程,使用以下查询:

select object_name, object_type, status
from sys.all_objects 
where owner = '<remote_schema>' and 
      object_name = '<remote_proc_name>' and 
      object_type in ('PROCEDURE', 'FUNCTION', 'PACKAGE', 'PACKAGE BODY')

对于 Sybase 过程,按 passthru 模式对 Sybase 服务器使用以下查询:

select id
from dbo.sysobjects 
where id = object_id('<remote_schema>.<remote_proc_name>') and
      (type = 'P' or type ='XP')

如果以上任何查询无法返回所需的远程过程,那么在执行 CREATE PROCEDURE 期间会抛出错误 SQL1253N。

示例

以 Oracle 为例,假设执行以下 SQL 语句:

CREATE PROCEDURE FSTP1 SOURCE "J15USER1"."ORA1"
                       NUMBER OF PARAMETERS 3
                       FOR SERVER SERV

返回以下错误,表示没有找到具有这个名称的过程。

DB21034E The command was processed as an SQL statement because it was
not a valid Command Line Processor command.  During SQL processing it
returned: SQL1253N The source procedure with the name "J15USER1.ORA_1"
was not found at the data source. Reason code = "5".  LINE NUMBER=1.
SQLSTATE=42883

第一步是使用上面给出的查询检查 Oracle 编目表,判断这个过程是否存在。如果按照 passthru 模式运行以下查询,它可能不返回行:

select owner, package_name, object_name, overload, parm_count
from   (
         select owner, package_name, object_name, overload,
                sum(case when data_type is null then 0 else 1 end) as parm_count 
         from sys.all_arguments 
         where data_level = 0
         group by owner, package_name, object_name, overload
       ) aa
where  object_name = 'ORA1' and
       package_name IS NULL and
       owner = 'J15USER1' and
       parm_count = 3


OWNER    PACKAGE_NAME OBJECT_NAME OVERLOAD PARM_COUNT
-------- ------------ ----------- -------- ----------

0 record(s) selected.

为了了解为什么没有找到过程,可能需要修改查询,去掉一些搜索条件。假设首先去掉限制包名的条件:

select owner, package_name, object_name, overload, parm_count
from   (
         select owner, package_name, object_name, overload,
                sum(case when data_type is null then 0 else 1 end) as parm_count 
         from sys.all_arguments 
         where data_level = 0
         group by owner, package_name, object_name, overload
       ) aa
where  object_name = 'ORA1' and
       owner = 'J15USER1' and
       parm_count = 3

OWNER    PACKAGE_NAME OBJECT_NAME OVERLOAD PARM_COUNT
-------- ------------ ----------- -------- ----------------------
J15USER1 NEWTON_PACK1 ORA1        2        +3.00000000000000E+000

1 record(s) selected.

现在看到了所需的过程,并知道应该指定包名。修正后的数据定义语言(DDL)语句如下:

CREATE PROCEDURE FSTP1 SOURCE "J15USER1"."NEWTON_PACK1"."ORA1"
                       NUMBER OF PARAMETERS 3
                       FOR SERVER SERV

DB20000I  The SQL command completed successfully.

调用联邦过程

在可以调用 DB2 过程的大多数地方都可以调用联邦过程。但是,对于联邦过程调用有几个限制。如果对联邦过程的调用失败了,检查这是否是由于以下原因造成的:

  • 如果过程的访问级别是 READS SQL DATA 或 MODIFIES SQL DATA,那么它在外部 UDF 中会阻塞并返回错误 SQL20136。
  • 如果访问级别是 MODIFIES SQL DATA,那么它在触发器、动态合成语句、SQL 体函数中或在创建保存点时会阻塞,并返回原因码为 22 的错误 SQL30090。
  • 如果远程过程返回不受支持的结果集类型,比如 LOB 或 XML,那么 CALL 返回错误 SQL3324N。在这种情况下,远程过程已经执行,但是没有返回结果集。
  • 如果返回原因码为 21 的错误 SQL30090,那么有不同的原因,例如试图在 fenced 包装器上创建联邦过程,或者在联邦的两阶段提交模式中 Oracle 过程包含提交。

可以使用 db2expln 工具解释 CALL 语句。假设 CALL 语句是 CALL fstp1(10,?),下面是 db2expln 输出:

db2expln -d fspdb -statement "CALL fstp1(10,?)" -terminal

******************** DYNAMIC ***************************************

==================== STATEMENT ===========================
        Isolation Level          = Cursor Stability
        Blocking                 = Block Unambiguous Cursors
        Query Optimization Class = 5
        Partition Parallel       = No
        Intra-Partition Parallel = No
        SQL Path                 = "SYSIBM", "SYSFUN", "SYSPROC",
                                   "SYSIBMADM", "NEWTON"

Statement:
  CALL fstp1(10, ?)

Section Code Page = 819

Estimated Cost = 0.004800
Estimated Cardinality = 0.000000

Return Data to Application
  #Columns = 1

Federated Procedure #1:
Server: SERV  (ORACLE 9.1.1)
SQL Statement:
  BEGIN "J15USER1" ."NEWTON_PACK1" ."ORA1" ( +1.00000000000000E+001,
             :H0 , :H1 ); IF :H0%isopen
     then :R0 :=1;
     else :R0 :=0; END IF; END;

End of section

注: 远程语句在内部使用一些附加逻辑来检查空结果集。它还说明了参数是如何转换的。

CALL 语句的事务问题

联邦过程中使用的远程过程不应该对当前事务进行提交或回退,因为这会导致数据不一致。在这种情况下,联邦数据库无法保证事务性行为。本节描述远程过程中的 COMMIT 和 ROLLBACK 操作造成的一些问题,并给出避免这些问题的一些建议。

在联邦的两阶段提交环境中,如果 Oracle 过程的过程体中有 COMMIT 操作(对于类型 1 和 2 两种向内连接),那么联邦过程返回以下错误:

call fstp1(10,?)
SQL30090N  Operation invalid for application execution environment.
Reason  code = "21".  SQLSTATE=25000

整个过程体都没有执行。

另一方面,如果在过程体中有回滚,那么数据源会回滚在回滚语句之前在同一数据源上发出的所有语句,但是在联邦服务器和其他数据源上却不进行回滚。

Oracle 有一个有用的特性,可以帮助应用程序设计人员解决这些问题。这个特性称为 “自治事务(autonomous transaction)”。例如,过程可能希望在执行数据操纵语言(DML)语句之前提交一个 DDL 语句。下面的代码说明如何将 DDL 语句隔离到一个自治事务中,而不必提交联邦服务器所发起的事务:

set passthru SERV

create table t1 (c1 int)

-- create Oracle package
CREATE OR REPLACE PACKAGE tran_pack AS 
procedure prep_table; procedure do_insert(v in number); 
END tran_pack;

-- create package body with two Oracle procedures
CREATE OR REPLACE PACKAGE BODY tran_pack AS 
    procedure prep_table is 
      pragma autonomous_transaction; 
    begin delete from t1; commit; end; 

    procedure do_insert (v in number) is 
    begin prep_table(); insert into t1 values(v); end; 

END tran_pack;

--verify the procedures created
select owner, package_name, object_name, overload, parm_count
from 
    (
      select owner, package_name, object_name, overload,
             sum(case when data_type is null then 0 else 1 end) as parm_count   
      from sys.all_arguments
      where data_level = 0
      group by owner, package_name, object_name, overload
    ) aa
where object_name = 'PREP_TABLE' and 
      package_name = 'TRAN_PACK' and 
      owner = 'J15USER1' and 
      parm_count = 0

OWNER      PACKAGE_NAME OBJECT_NAME OVERLOAD  PARM_COUNT
---------- ------------ ----------- --------- ---------------
J15USER1   TRAN_PACK    PREP_TABLE  -         +0.0000000E+000

select owner, package_name, object_name, overload, parm_count
from 
    (select owner, package_name, object_name, overload,
     sum(case when data_type is null then 0 else 1 end) as parm_count   
    from sys.all_arguments  where data_level = 0
    group by owner, package_name, object_name, overload) 
where object_name = 'DO_INSERT' and 
      package_name = 'TRAN_PACK' and 
      owner = 'J15USER1' and 
      parm_count = 1


OWNER      PACKAGE_NAME OBJECT_NAME OVERLOAD  PARM_COUNT
---------- ------------ ----------- --------- ---------------
J15USER1   TRAN_PACK    DO_INSERT   -         +1.0000000E+000

set passthru reset

create procedure ora_insert source "J15USER1"."TRAN_PACK"."DO_INSERT"
                            for server SERV

alter server SERV options (set DB2_TWO_PHASE_COMMIT 'Y')

update command options using c off

call ora_insert(3)

  Return Status = 0

commit
DB20000I  The SQL command completed successfully.

select * from nt1

C1
------------------------
  +3.00000000000000E+000

  1 record(s) selected.


call ora_insert(4)

  Return Status = 0

rollback
DB20000I  The SQL command completed successfully.

select * from nt1

C1
------------------------

  0 record(s) selected.

在 Sybase 中,远程过程中的 ROLLBACK 和 COMMIT 可能会导致更多问题。当前,Sybase 包装器采用 “非连锁模式(unchained mode)”。如果在 Sybase 远程过程中需要事务(COMMIT 或 ROLLBACK),那么应该在远程过程中包含 “begin transaction” 语句,从而恢复非连锁模式。否则,连接会切换到连锁模式。过程体中的 ROLLBACK 会对事务中的所有语句进行回滚,即使是过程之外的语句也会回滚。即使启用了联邦的两阶段提交模式,远程过程中的 COMMIT 也可能会导致数据不一致。下面是一个例子:

set passthru s1;

create table t1 (c1 int, c2 char(40));
insert into t1 values (1, 'test');

create procedure sybase_rollback as
begin transaction
insert into t1 values (10, 'before unchained rollback')
rollback;

create procedure sybase_commit as
begin transaction
insert into t1 values (20, 'before unchained commit')
commit;

set passthru reset;

create procedure unchained_rollback source "j15user1"."sybase_rollback" for server s1;
create procedure unchained_commit source "j15user1"."sybase_commit" for server s1;
create nickname sb_n for s1."j15user1"."t1";
commit;

alter server s1 options (set DB2_TWO_PHASE_COMMIT 'Y');
update command options using c off;
delete from sb_n;
commit;
select * from sb_n;
C1          C2                                       
----------- ----------------------------------------
  0 record(s) selected.  

insert into sb_n values (100,'before call unchained_rollback');
select * from sb_n;

C1          C2                                      
----------- ----------------------------------------
 
        100 before call unchained_rollback             
  1 record(s) selected. 

call unchained_rollback();
SQL1822N  Unexpected error code "266" received from data source "S1". 
Associated text and tokens are "Transaction count after EXECUTE indicates that 
a COMMIT or ROLL".  SQLSTATE=560BD 
--  All the transaction is rollback including these before CALL

select * from sb_n;

C1          C2                                      
----------- ----------------------------------------
  0 record(s) selected. 

call unchained_commit();
  Return Status = 0

select * from sb_n;

 C1          C2                                      
----------- ----------------------------------------
         20 before unchained commit                   
  1 record(s) selected. 

select * from t1;
C1
-----------
  0 record(s) selected.

insert into t1 values (10);
DB20000I The SQL command completed successfully. 

-- commit fails all the transaction is rollback except the transaction in procedure
-- data inconsistent occurs
 
commit;

SQL0903N  COMMIT statement failed, transaction rolled back.  Reason code: "2". 
SQLSTATE=40504 

-- local transaction is rolled back

select * from t1;
C1
-----------
   0 record(s) selected. 

-- remote transaction due to procedure call is not rolled back
select * from sb_n;
C1          C2
----------- ----------------------------------------
         20 before unchained commit                   
   1 record(s) selected.

connect reset;
DB20000I  The SQL command completed successfully.  

使用结果集

如果没有将结果集返回给客户机或调用者,那么可能是由于以下原因之一:

  • 定义为 “返回给调用者” (默认设置)的结果集只能由调用者获取。调用者可以是另一个 DB2 过程或客户机应用程序。定义为 “返回给客户机” 的结果集不能由嵌套的过程访问,只能由最初的应用程序获取。这些定义在联邦过程的 CREATE PROCEDURE 语句中决定,而不是数据源上。
  • 在触发器或用户定义函数中调用联邦过程。
  • 在 CREATE PROCEDURE (Sourced) 语句中没有正确地定义联邦过程。
  • 应用程序是使用嵌入式 SQL 编写的。还要检查客户机对处理结果集是否有任何其他限制。
  • 正如 限制 一节中提到的,不支持可持有结果集。如果结果集是在前一个事务中生成的,那么隐式或显式的提交会关闭这个结果集。
  • 联邦过程只返回第一个结果集。如果远程过程的结果集次序不总是相同的,那么根据哪个结果集在最前面,联邦过程可能返回不同的结果集。例如,数据源上的远程过程 A 定义为:

    create procedure A ()
    begin
      declare cur1 cursor with return to client
        for select * from t;
    
      open cur1
    end
    

    数据源上的远程过程 B 定义为:

    create procedure B (arg1 int)
    begin
      declare cur2 cursor with return to client
        for select * from t;
    
      if (arg1 < 10) then
        call A();
      end if;
      open cur2; 
    end 
    

    为远程过程 B 创建联邦过程 FedP1:

    CREATE PROCEDURE FEDP1 SOURCE B
                           FOR SERVER S1
                           NUMBER OF PARAMETERS 1
                           WITH RETURN TO CLIENT ALL
    

    有一个本地 UDB 过程 P1,它调用联邦过程,其定义如下:

    CREATE PROCEDURE P1 (ARG1 INT)
    BEGIN
      CALL FEDP1(ARG1)
    END 
    

    而应用程序调用这个 UDB 过程:

    CALL P1(1);   -- Result set CUR1 will be returned, CUR2 is not returned
    CALL P1(20);  -- Result set CUR2 will be returned
    





回页首


未来

计划对联邦过程支持进行改进,消除一些限制并添加其他数据源支持,比如:

  • 提供 fenced 包装器支持。
  • 支持 ALTER PROCEDURE 以便修改参数数据类型。
  • 支持其他数据源,比如 DRDA、Microsoft SQL Server 和 Informix。
  • 对 Oracle 和 DRDA 数据源支持多结果集。


参考资料

学习

获得产品和技术
  • 使用 IBM 试用软件 构建您的下一个开发项目,这些软件可以从 developerWorks 直接下载。


讨论


作者简介

Hans Zeller 于 2004 年加入 IBM 联邦开发团队。他从事存储过程、异步、WebSphere Federation Server V9 的性能和 2PC 特性的相关工作。在此之前,Hans 在 Tandem、Compaq 和 HP 工作了 15 年,从事并行可伸缩数据库系统和查询优化工作。他拥有德国 University of Stuttgart 的计算机科学博士学位。


Qinglong Hu 于 2000 年加入 IBM,现在从事联邦技术。他曾经参与存储过程、联邦 passthru SQL、2PC、Data Links 和 DB2 Everyplace 的性能研究。在加入 IBM 之前,他是加拿大滑铁卢大学的研究人员,研究移动计算的数据管理。他拥有香港科技大学的计算机科学博士学位。


Dimple Bhatia 于 2000 年加入 IBM,现在在 Websphere Federation Server 团队中从事联邦技术。在从事联邦技术之前,她在 Business Intelligence 中从事 Data Warehousing 项目。在加入 IBM 之前,她为新泽西州朗讯技术公司工作。她拥有纽约 Syracuse University 的计算机工程硕士学位。




对本文的评价










回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款