找回密码
 注册
搜索
热搜: 回贴
微赢网络技术论坛 门户 安全攻防 查看内容

在IBMDB2通用数据库中实现会话间的警告

2009-12-14 02:55| 发布者: admin| 查看: 26| 评论: 0|原作者: 仙之剑缘

您是否正将您的数据库从Oracle迁移至 IBM? DB2? Universal Database??您是否认为可能会丢失 Oracle 的某个特殊功能?DB2 UDB 就是这样一种十分灵活的数据库,它可以满足您的许多需要。在本文中,我将介绍一下如何实现一个称为警告的功能。警告用于允许多重会话之间的通信。
警告概述
如图1中所显示,警告是为在会话间传递消息而设计的。警告标识、会话标识和消息存储在表中(这里是 alerts.dbms_alert_info)。消息由一个会话发送再由另一个会话读取,这个过程由一个在指定表中设置的标志来控制。在设计参数(像列长度、主机变量长度、轮询时间间隔等)时需要了解 Oracle 到 DB2 的迁移情况。您可以根据需要增加警告名和消息长度的大小。
图 1. 警告在会话间发送消息


设计概述
以下对象在实现类似 Oracle 具有的警告功能时都是必需的。所有对象都包含在本文的 下载部分中:
存储警告信息的表: alerts.dbms_alert_info
注册警告的存储过程: alerts.register
删除警告的存储过程: alerts.remove和 alerts.delete
发送警告消息的存储过程: alerts.signal
接收警告消息的存储过程: alerts.waitone和 alerts.waitany
实现延迟的 UDF: alerts.delay
实现会话标识的 UDF: alerts.session_id

您可以更改我的设计以满足自己的特殊要求。所有对象都使用了一个共同的模式,即警告。设计存储过程以便您可以扩展它们来捕获 SQLCODE、SQLSTATE 和 ERROR_MESSAGE。大量的异常处理在上面列出的所有存储过程中实现,但是这里并没有使用到。您可以取消样本代码中异常处理部分的注释然后再使用该部分。它们也可以返回相应的返回码,以便用主语言实现必需的操作。游标可以在所有存储过程中实现,但是在一些地方您可能希望更改为 fullselect。所有警告对象都被授予了公共执行(Public execute)许可权。您应该使用 DBADM 或 SYSADM 权限创建所有这些对象。

存储警告信息:alerts.dbms._alert_info

目标:该表存储警告标识、会话标识、消息和标志。该标志是一个指示符,表明一条消息是否已经由所有者会话放置在表中。

该表有四列:

NAME
该列(主键)存储了警告名的名称。在 Oracle 中,name 是一个可变长度为 30 个字符的字段,然而这里我们将它定义为 varchar(60)。当然您可以扩展您的命名模式。

SID
这是会话标识。使用一个用户定义的函数(session_id())来标识会话标识。

MESSAGE
用户会话发送的警告消息正文,这个用户会话需要和其他会话进行通信。它定义为使用 1800 个字符,但是如果您希望的话,可以扩展它的长度。
CHANGED
这是前面描述的指示符标志。缺省值是“N”。

授权:授予 PUBLIC 的权限包括:SELECT、INSERT、UPDATE、DELETE

CREATE TABLE ALERTS.DBMS_ALERT_INFO (
NAME VARCHAR(60) NOT NULL ,
SID VARCHAR(50) NOT NULL,
MESSAGE VARCHAR(1800) ,
CHANGED CHAR(1) NOT NULL WITH DEFAULT 'N',
CONSTRAINT PK_DBMS_ALERT_INFO PRIMARY KEY (NAME),
CONSTRAINT CC_DBMS_ALERT_INFO CHECK (CHANGED IN ('Y','N','y','n')));
注册警告:alerts.register

目标:该存储过程注册警告名。

相关性:session_id() UDF

输入参数:警告名(最大长度为 60 个字符)

输出参数:SQLCODE、SQLSTATE 和 ERROR_MESSAGE(以备扩展使用)

授权:将 EXECUTE 授权给 PUBLIC

功能行为:该存储过程注册警告名和会话标识并存储这些内容。它将 MESSAGE 字段设置为 null 并将 CHANGED 字段设置为“N”。成功的话返回 0;否则返回 -1。
从会话中删除已经注册的警告名(该警告名由这个会话创建):alerts.remove

目标:从 alerts.dbms_alert_info 表删除注册警告名。

相关性:session_id() UDF

输入参数:警告名(最大长度为 60 个字符)

输出参数:SQLCODE、SQLSTATE 和 ERROR_MESSAGE(以备扩展使用)

授权:将 EXECUTE 授权给 PUBLIC

功能行为:会话使用此存储过程删除一个注册警告。此存储过程检查 alerts.dbms_alert_info 表中是否存在警告名。然后还将检查当前会话标识是否和即将删除的警告注册的会话标识匹配。如果不匹配,将无法删除指定的警告。用这种方式我们可以确保一个会话删除它自己创建的警告。如果成功的话返回 0;否则返回 -1。

从任何会话删除一个注册警告名:alerts.delete

目标:从 alerts.dbms_alert_info 表中删除一个注册警告名

相关性:无

输入参数:警告名(最大长度为 60 个字符)

输出参数:SQLCODE、SQLSTATE 和 ERROR_MESSAGE(以备扩展使用)

授权:将 EXECUTE 授权给 PUBLIC

功能行为:该存储过程和 alerts.remove 的功能完全一样,除了 任何会话都可以从 alerts.dbms_alert_info 表删除指定的警告名。

发送警告消息:alerts.signal

目标:发送警告消息至注册警告。

相关性:无

输入参数:警告名(最大长度为 60 个字符),警告消息(最大长度为 1800 个字符)

输出参数:SQLCODE、SQLSTATE 和 ERROR_MESSAGE(以备扩展使用)

授权:将 EXECUTE 授权给 PUBLIC

功能行为:该存储过程首先检查指定警告名是否存在以及其标志是否设置为“N”。这个标志意味着此会话可以发送警告消息至注册警告,因为没有其它的会话发送或阻塞该特定的注册警告。如果成功的话返回 0;否则返回 -1。

等待并读取特定警告:alerts.waitone

目标:存储过程等待并从指定警告名中读取警告消息。

相关性:delay() UDF

输入参数:警告名(最大长度为 60 个字符)

输出参数:SQLCODE、SQLSTATE、ERROR_MESSAGE(以备扩展使用)、警告消息和超时状态。

授权:将 EXECUTE 授权给 PUBLIC

功能行为:该存储过程首先检查指定警告名是否存在以及其标志是否设置为“Y”。这个标志意味着此会话可以从一个注册警告接收警告消息,因为另一个会话已经发送了一条消息,而此会话正在查找来自那个会话的消息。

这个存储过程等待警告消息。如果该警告没有消息,它将等待一个预定义的时间间隔然后再检查。缺省轮询时间间隔是 5 秒,但是如果超时输入参数设置为少于 5 秒或不是 5 秒的倍数,则轮询时间间隔将设置为 1 秒。阅读完消息以后,此存储过程清除消息字段并将标志重新设置为“N”以使其不会阻塞其它会话。现在其它会话可以使用注册警告发送消息。如果成功的话返回 0;否则返回 -1。

等待并读取任何警告消息:alerts.waitany

目标:等待并从任意警告名中读取警告消息的存储过程。

相关性:delay() UDF

输入参数:超时值,按秒计。

输出参数:SQLCODE、SQLSTATE、ERROR_MESSAGE(以备扩展使用)、发出消息的警告名、消息和超时状态。

授权:将 EXECUTE 授权给 PUBLIC

功能行为:waitone 和 waitany 存储过程的差别在于,waitany 从 任何警告名中查找消息并将该警告名作为输出参数返回。waitone 从指定警告名查找消息。

这两个存储过程的另一个不同就是轮询时间间隔。对于 waitany,默认的轮询时间间隔设置为 1 秒并且在每个轮询周期中按指数级增加。如果超时时间间隔小于某个轮询周期,则在开始此轮询周期之前,此存储过程将以该超时状态结束。如果成功的话返回 0;否则返回 -1。

延迟执行:alerts.delay

目标:DB2 UDB 中没有任何诸如“delay”或是“sleep”的系统调用,因此我们无法通过它们来将执行暂挂一段指定时间。该 UDF 通过运行一个在 Java? 中实现的称为“sleep”的系统调用,以在执行中实现延迟。

相关性:无

输入参数:延迟时间,以秒计。

输出参数:0(成功),-1(失败)

授权:将 EXECUTE 授权给 PUBLIC

功能行为:该函数使用 OS 调用来实现延迟,这比其它任何一种类型的实现都更加高效。

目录语句: CREATE FUNCTION delay(INTEGER)
RETURNS INTEGER
EXTERNAL NAME 'delayUDFjar:delayUDF.DELAY(INTEGER)'
LANGUAGE JAVA
PARAMETER STYLE JAVA
NOT DETERMINISTIC
NO SQL
FENCED
RETURNS NULL ON NULL INPUT
EXTERNAL ACTION;
捕获会话标识:alerts.session_id

目标:捕获会话标识的用户定义的函数。

相关性:无

输入参数:延迟时间,以秒计。

输出参数:0(成功),-1(失败)

授权:将 EXECUTE 授权给 PUBLIC

功能行为:该函数捕获存储在 SQLUDF_DBINFO 内部结构中的会话标识。

目录语句: CREATE FUNCTION SESSION_ID() RETURNS CHAR(34)
EXTERNAL NAME 'sessionUDF!SESSION_ID'
FENCED
LANGUAGE C
PARAMETER STYLE DB2SQL
NOT VARIANT
NO SQL
NO EXTERNAL ACTION
DBINFO;
安装警告样本

必备软件:Microsoft VC v6.0 和 JDK v1.3.1。必须在操作系统环境设置中启用这两个编译器路径。
1.将文件 alert.zip 解压缩至一个文件夹中,例如 C:\temp\alert
2.打开 alertsetup.bat 批处理文件并用适当的值编辑以下两行。

·在 DB2HOMEPATH=C:\SQLLIB 中,适当地更改 SQLLIB 路径。
·在以下行中,更改路径至 C:\temp\alert\delayUDF.jar :
DB2 CALL SQLJ.INSTALL_JAR('file:C:\Documents and Settings\sudipta\My Documents\db2\KnowledgeBase\article\alert\delayUDF.jar','delayUDFjar')

3.在 DB2 Command Window 中运行批处理文件:
alertsetup.bat
例如: C:\temp\alert>alertsetup.bat SAMPLE TEST TEST01
DB2 UDB V8 测试过程

1.打开两个 DB2 COMMAND WINDOW 会话(启用了 DB2 环境的命令窗口)。让我们将一个会话表示为“会话 A”,另一个表示为“会话 B”。
2.在两个会话中,连接至 SAMPLE 数据库。
3.在会话 A 中执行:
db2 call alerts.register('abc')
4.在会话 A 中执行:
db2 call alerts.signal('abc','Hello World from Session A.....')
5.在会话 B 中执行:
db2 call alerts.waitone('abc',?, ?, 30)
6.在会话 A 中执行:
db2 call alerts.register('xyz')
7.在会话 A 中执行:
db2 call alerts.signal('xyz','Message through alert xyz....')
8.在会话 B 中执行:
db2 call alerts.waitany(?,?,?,30)
9.在会话 B 中执行:
db2 call alerts.remove('abc')
这条语句将失败,因为会话 B 不是名为“abc”的警告的创建者。
10.在会话 A 中执行同样的命令:
db2 call alerts.remove('abc')
这次将成功。
11.在会话 B 中执行:
db2 call alerts.delete('xyz')
这次将成功,因为 alerts.delete 设计为可以从任何会话删除任何注册警告。
12.在两个 CLP 会话中执行 db2 terminate 以终止连接。


最新评论

QQ|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏ICP备08020429号 )

GMT+8, 2024-9-30 15:25 , Processed in 0.219194 second(s), 12 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

返回顶部