Oracle PL/SQL进阶编程(第八弹:使用系统包:DBMS_ALERT)

报警是Oracle中单向的、以事务提交为基础的对数据库报警事件的异步报警通知,比如可以在数据库数据发生变化时,某个字段的值发生变化时,通过报警向用户发送电子邮件通知。
报警是基于事务的,意味着除非能够报警的事务被提交,否则等过过程中的事务不会获得报警。

要使用DBMS_ALERT包,需要以DBA身份登录,为用户赋权:
GRANT EXECUTE ON DBMS_ALERT TO scott;

报警需要定义报警的发布方和接收方,对应同一个会话中的两个进程或者是不同会话中的进程。一个程序可以注册多个命名的报警,然后使用WAIT和WAITANY等待其中的任何一个报警产生。

注册报警事件REGISTER

在一个会话中可以注册多个报警,语法如下:
DBMS_ALERT.REGISTER(name IN VARCHAR2);

等待特定报警WAITONE

该过程用于等待当前会话中特定的报警事件,并且在发生报警事件时输出报警消息,该过程在执行之前会隐含地发出COMMIT,语法如下:

DBMS_ALERT.WAITONE(name    IN VARCHAR2,
                   message OUT VARCHAR2,
                   status  OUT INTEGER,
                   timeout IN NUMBER DEFAULT MAXWAIT);

name是等待报警的名称,message用来返回报警信息,该信息是由SIGNAL发布报警时发布的,如果有多个此类报警在WAITONE过程执行前发生,那么只返回最近的报警发布信息,其他的将被丢弃。status在报警发生时会返回0,如果超时,返回1。timeout是等待报警发生时的时间,如果在此时间内无报警发生,则status返回1。

等待任意报警WAITANY

WAITANY过程会等待会话中已经注册的任何报警的发生,在这个过程执行前会有一个隐含的COMMIT被执行,同样,在等待这个报警发生的同事还可以发布某些报警。语法如下:

DBMS_ALERT.WAITANY(name    OUT VARCHAR2,
                   message OUT VARCHAR2,
                   status  OUT INTEGER,
                   timeout IN NUMBER DEFAULT MAXWAIT);

参数大部分与WAITONE相同,只是name参数为输出参数,用来返回等待报警的名称。

删除报警REMOVE

DBMS_ALERT.REMOVE(name IN VARCHAR2);

删除所有报警REMOVEALL

这个过程会删除会话中所有注册表中的报警,该过程会在一个会话开始时被自动调用,总是执行COMMIT。
DBMS_ALERT.REMOVEALL;

时间间隔设置SET_DEFAULTS

用于设置检测报警时间的时间间隔,默认时间间隔为5秒。
DBMS_ALERT.SET_DEFAULTS(sensitivity IN NUMBER);

设置报警消息SIGNAL

该过程用于指定报警时间所对应的报警消息,只有在提交事务是才会发生报警信息,而当回退事务是不会发生报警信息的。
DBMS_ALERT.SIGNAL(name IN VARCHAR2, message VARCHAR2);
消息长度不能超过1800字节。

多个会话可以并发执行同一个报警,每个会话发布报警时会阻塞其他会话发布的报警,直到报警被提交,因此事务会以序列的方式发生。

为了演示报警,是用两个会话来进行测试。在第一个会话中创建如下的PL/SQL匿名块,等待报警发生:

DECLARE
   v_alertname   VARCHAR2 (30)  := 'alert_demo';    --报警名称
   v_status      INTEGER;                           --等待状态
   v_msg         VARCHAR2 (200);                    --报警消息
BEGIN
    --注册报警,指定报警名为alert_demo
   DBMS_ALERT.REGISTER (v_alertname);
   --监听报警,等待报警发生
   DBMS_ALERT.waitone(v_alertname, v_msg, v_status);
   --如果不返回0,表示报警示败
   IF v_status != 0
   THEN
      DBMS_OUTPUT.put_line ('error');        --显示错误消息
   END IF;
   DBMS_OUTPUT.put_line (v_msg);             --显示报警消息
END;

可以看到,在代码中注册了一个名为alert_demo的报警,然后调用waitone等待报警,如果在SQL*Plus执行这段代码,可以看到整个界面被阻塞了,等待有报警产生。下面的代码将使用SIGNAL定义报警消息,并使用COMMIT语句发出报警:

DECLARE
   v_alertname   VARCHAR2 (30) := 'alert_demo';
BEGIN
    --向报警alert_demo发送报警信息
   DBMS_ALERT.signal (v_alertname, 'dbms_alert测试!');
   COMMIT;             --触发报警,如果是ROLLBACK,则不触发报警。
END;

可以看到,当这段匿名的语句块一执行,报警的等待会话就会打印出在SIGNAL中指定的报警文本,并退出等待状态。

可以看到报警这种机制可以实现多个会话交互,但是有许多局限性,比如一旦开始等待,进程将不再做任何事情,因此是双方难以交互。但是DBMS_ALERT在很多地方的作用也是无可替代,这里先不加以详细阐述。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章