WEB开发网
开发学院数据库DB2 在 DB2 Universal Database 中实现管道 阅读

在 DB2 Universal Database 中实现管道

 2009-12-08 00:00:00 来源:WEB开发网   
核心提示:简介在我的前一篇文章 在 DB2 通用数据库中实现会话间警告 中,您看到了如何使用两个数据库会话之间的警告(alert)来实现一条通信通道,在 DB2 Universal Database 中实现管道,本文为数据库会话间的通信提供了另一种实现,这种实现使用消息管道,因此在错误消息发送时不存在冲突问题, 错误代码的定义嵌

简介

在我的前一篇文章 在 DB2 通用数据库中实现会话间警告 中,您看到了如何使用两个数据库会话之间的警告(alert)来实现一条通信通道。本文为数据库会话间的通信提供了另一种实现,这种实现使用消息管道。警告和管道两者都可以在异步和同步两种模式之一中发挥作用。两者的不同之处是,管道可以将单个消息的分组(packet)从一个会话传输到另一个会话,而使用警告是不可能做到这一点的。警告多用于根据另一个会话中的事件采取某种行动。通过使用管道,您可以将由不同数据类型组成的消息分组实实在在地从一个会话传输到另一个会话。这种实现类似于 Oracle DBMS_PIPE 包,但还是有些变化。如果您要将应用程序从 Oracle 移植到 DB2 Universal Database,那么这种实现非常有用。

这种管道包(pipe package)的实现包含:

3 个 catalog 表

2 个用户定义函数

28 个 SQL 存储过程

工作原理

这里应该有两个参与的会话。其中一个会话(假设为 A)准备好消息分组并将其发送到数据库编目(catalog)。另一个会话(假设为 B)读取由 A 发送的消息分组,然后关闭管道。

会话 A 做以下事情:

创建一个命名管道,可以使用大小限制,也可以不使用大小限制,管道的类型可以是 public 或 private 。

将消息打包到一个命名的管道或临时的管道中,这里要求管道是打开的,并且存在于此会话中。 如果命名的管道不存在,那么它就创建一个临时的 public 类型的大小不限的管道,并打包消息。如果该管道的类型为 private ,那么此管道中的所有消息都要加密。

如果消息分组由多条消息组成,则继续打包。

发送该消息分组。如果管道是一个临时管道,那么为此临时管道提供一个名字。

会话 B 做以下事情:

接收命名的管道并打开它。

检查消息的数据类型。检查和读取消息的顺序是 FIFO (First In First Out,先进先出)。在检查了数据类型之后,会话 B 将相同的信息通知给调用应用程序。

之后调用者应用程序将消息解包并存储在一个适当的变量(数据类型非常重要)中。如果管道的类型为 private ,那么先要对消息解密,然后再读取它。如果在管道中再没有其他的消息,则关闭管道。否则,继续重复执行步骤 2 和步骤 3。

除了上述功能行为之外,还有另外三个可用于管道管理的功能:

创建命名管道的用户可以删除处于关闭状态的这个管道。

不管命名管道是由哪个用户创建的,数据库管理员都可以删除处于关闭状态这个管道。

创建命名管道的用户可以清除和重新使用处于关闭状态的这个管道。


图 1. 创建、打包和发送一个管道
在 DB2 Universal Database 中实现管道

查看原图(大图)

图 2. 接收、检查一个管道并对这个管道解包
在 DB2 Universal Database 中实现管道

查看原图(大图)

设计视图

在 DB2 Universal Database 中实现了三种类型的对象,用以支持管道功能。本文的下载文档中提供了所有这些对象。

catalog 表

DBMS_PIPE.PIPES——存储管道的定义

DBMS_PIPE.PIPEMEMBERS——以纯字符串格式存储消息

DBMS_PIPE.PIPEMEMBERS_ENCRYPT——以加密字符串格式存储消息

用户定义的函数

DBMS_PIPE.DELAY——提供按秒计的延时

DBMS_PIPE.SESSION_ID——从数据库管理器中捕捉会话 ID

注意: 在 DB2 通用数据库中实现会话间警告 一文中提供了这两个函数的源代码。这里同样使用了这两个函数,但这些函数已经是经过编译的。

SQL 存储过程

DBMS_PIPE.CREATE_PIPE——创建一个命名管道,3 Nos,被重载

DBMS_PIPE.PACK_MESSAGES_xxxx——将消息打包到管道中,9 Nos,用于不同数据类型

DBMS_PIPE.SEND_MESSAGE——发送管道以用于处理,2 Nos,被重载

DBMS_PIPE.RECEIVE_MESSAGE——检索管道以用于读取

DBMS_PIPE.NEXT_ITEM_TYPE——检查第一个打包的而未检查过的消息数据类型

DBMS_PIPE.UNPACK_MESSAGES_x——读取消息并关闭管道,9 Nos,用于不同数据类型

DBMS_PIPE.PURGE——清除管道中的消息并将管道状态重置为 PACKING

DBMS_PIPE.REMOVE_PIPE——由创建者从系统中删除一个管道

DBMS_PIPE.DELETE_PIPE——由管理员删除一个管道

DBMS_PIPE.PIPES catalog 表有 8 个字段:

PID——管道 ID

PNAME——管道名

PTYPE——管道类型(Y - Private,N - Public)

POWNER——管道创建者的名字

PSTATUS——管道的状态(P - Packing, S - Sent, O - Open, R - Reading, C - Closed)

PNDATA——管道中消息的编号

PSIZE——管道的大小限制(按字节计)

PTEMPNAME——管道的临时名字(设置为会话 ID)

DBMS_PIPE.PIPEMEMBERS catalog 表有 6 个字段:

SLNO——一个序列号

PID——管道 ID(使用外键链接到 PIPES.PID)

MID——管道中的成员/消息 ID

MTID——成员/消息数据类型 ID(下面将提到)

NDIF——成员/消息的状态(N:未检查,C:已检查,R:读取)

DATA——成员/消息数据(纯字符串格式)

DBMS_PIPE.PIPEMEMBERS_ENCRYPT catalog 表也具有相同的字段,但是它以加密字符串的格式将数据存储在 DATA 字段中。

在下载中提供了四个实用程序。以 SYSADM 身份从 COMMAND WINDOW 执行这些程序,不要从 MS-DOS 窗口执行:

pipesetup.bat——编译所有的存储过程并注册前面提到的所有对象。

getroutines.bat——将所有 SQL 存储过程以二进制格式导出到 sar 文件中。

putroutines.bat——从 sar 文件导入所有 SQL 存储过程,但是不重新编译这些存储过程。

cleanup.bat——从数据库系统清除整个管道系统实现。

注意:为了编译 SQL 存储过程,需在服务器上提供 VC++ v5.0/v6.0 或 CYGWIN (Windows 下模拟的 Linux) GCC 以及 Java 编译器。如果没有 VC++ 编译器,那么可以使用 CYGWIN 的 GCC 编译器来编译同样的存储过程。

不同点、优点和局限性

管道功能是通过使用三个 catalog 表来实现的,这里并没有用到任何共享内存。因此,这些管道更加稳定,不受可用内存大小的影响。而且这种实现也更可靠,因为这里不存在对共享内存的直接访问途径,所有的数据操作都是由数据库服务器完成的。

对于消息的大小有一定的限制。每条消息最大可以达到 32631 字节。但是消息分组的大小(即管道大小)不存在任何大小限制,而在 Oracle 中,管道最大只能为 4 KB。

在对消息打包和解包时,需要不同的存储过程,因为存储过程是不能重载的。

数据类型为 LONG 或 LOB 的消息不能打包到管道中。不过,有一个方法可以做这件事。因此您可以同样实现它。

这个功能还可以在一个分为多个分区的环境中实现。在所有表中都应选择 PID 作为分区键(partitioning key),以使针对一个管道的所有信息都存储在相同的数据库分区中。

错误代码和返回代码

在出现错误时,只要在 DB2 Universal Database 文档中定义了错误代码,作为管道实现包的一部分而提供的例程(用户定义的函数和存储过程)都可以返回该错误代码。此外,以下是由例程返回的代码。

如果所有事项都是成功的,则返回0,但 NEXT_ITEM_TYPE 存储过程除外,该过程在成功时返回一个正的 5 位数值。每个数值代表一种数据类型:

数值 数据类型
99388time
99384date
99392timestamp
99452char (最多 254 个字符)
99448varchar (最多 32631 字符)
99500smallint
99496int
99492bigint
99484double

无论出现何种错误,用户定义函数都将返回 -1。

上述存储过程除了返回以下 DB2 Universal Database 服务器错误代码外,还返回一些用户定义的错误代码。

错误代码 解释
-9801被调存储过程的第一个参数是非法的
-9802被调存储过程的第二个参数是非法的
-9803被调存储过程的第三个参数是非法的
-9989管道正在使用中,不能清除消息,也不能删除管道
-9990管道中没有消息
-9991没有“打开”的管道可供读取消息
-9992没有接收消息的管道,或者管道不处于 SENT 状态
-9993没有访问该管道的权限
-9994管道名不匹配
-9995当前会话中没有可以发送的打开的管道
-9996该管道名已经在使用
-9997当前管道没有足够的空间
-9998当前管道不处于 PACKING 状态
-9999当前会话中至少有一个打开的管道

安装步骤

在 DB2 Universal Database 中可以用两种方法来实现这个‘pipe’功能:

使用实用程序 ....\\pipe\\sourceform\\pipesetup.bat 。
像下面这样执行该实用程序: Pipesetup.bat <database-name> <SYSADM userid> <SYSADM password> 

例子:

pipesetup.bat sample TEST TEST01

使用实用程序 ....\\pipe\\compiledform\\putroutines.bat .
像下面这样执行该实用程序: Putroutines.bat <database-name> <SYSADM userid> <SYSADM password> 

例子:

putroutines.bat sample TEST TEST01 

在执行上述任何一个实用程序前,都要做以下事情:

在文本编辑器(例如记事本)中打开实用程序。

更改这一行:
set DB2HOMEPATH=C:\\SQLLIB
,使其指向系统中正确的 SQLLIB 路径。

更改这一行:
DB2 -o- CALL SQLJ.INSTALL_JAR('file:C:\\Documents and Settings\\sudipta\\My Documents\\db2\\KnowledgeBase\\article5_inprogress\\pipe\\sourceform\\delayUDF.jar','delayUDFjar');
,使其指向 delayUDF.jar 文件所在的正确位置。

测试步骤

为了测试该管道系统:

打开两个 DB2 COMMAND WINDOW 会话(启用了 DB2 环境之后的命令窗口)。我们将其中一个会话命名为 Session A,另一个会话命名为 Session B。使用 SYSADM userid 连接到样本数据库(如果没有样本数据库,那么使用 db2sampl 命令创建一个)。如果您还没有创建‘pipe’系统,那么使用上述信息创建一个这样的系统。如果您将要多次运行该系统,那么不需要一次又一次地编译存储过程。在再次运行测试之前,应通过执行以下命令删除管道详细信息: db2 delete from dbms_pipe.pipes where pname='ABC'
.

在 session A 中:

定位到 .....\\pipe\\testscripts 目录。

执行命令: db2 -td@ -f send_packet.sql
该命令编译一个存储过程,这个存储过程负责创建一个管道,打包两条消息,并发送消息。

执行命令: db2 call dbms_pipe.send_packet()
您应该可以看到一个 0 (零)返回状态。

选择表 dbms_pipe.pipes和 dbms_pipe.pipemembers以查看详细信息。

在 session B 中:

定位到 .....\\pipe\\testscripts 目录。

执行命令 db2 -td@ -f read_packet.sql 。该命令编译一个存储过程,这个存储过程负责接收一个管道,检查数据类型,解包两条消息,最后关闭管道。

执行命令 db2 call dbms_pipe.read_packet(?, ?) 。您应该可以看到一个 -999010 返回状态(因为管道在检索最后一条消息,即 DATA2 之后被关闭),同时返回的还有 DATA1(time) 和 DATA2(date) 的数据。

选择表 dbms_pipe.pipes和 dbms_pipe.pipemembers以查看详细信息。

重要提示:

整个实现将使用 DB2 UDB 错误消息发送方法/代码来处理由于 SQL 错误或 DB2 UDB 系统中意外问题而引起的错误行为。除此之外,该实现还提供了作为管道功能行为一部分的定制错误代码和返回代码。

任何错误(逻辑功能错误、SQL 错误或 DB2 UDB 系统错误)都是以存储过程或函数的返回代码(数值)的形式被捕捉到。管道的逻辑错误是使用 -98XX 和 -99XX 错误代码系列捕捉的,对此 DB2 UDB 没有提供任何实现。只有存储过程 dbms_pipe.next_item_type 返回一个 5 位的数值代码,用以检查数据类型,并使用 dbms_pipe.unpack_message_x 存储过程采取行动。在本例中,DB2 UDB 没有提供任何使用 99XXX 系列的错误消息实现,因此在错误消息发送时不存在冲突问题。

错误代码的定义嵌入在每个源代码文件中。您可以在实现时灵活地选择自己的错误代码。

本文示例源代码或素材下载

Tags:DB Universal Database

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接