您是否正将您的数据库从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 以终止连接。 |
|小黑屋|最新主题|手机版|微赢网络技术论坛 ( 苏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.