DBMS_ALERT包提供了注册、发送和接收告警的能力。

表 1. DBMS ALERT 函数/存储过程

函数/存储过程

返回类型

说明

REGISTER(name)

N/A

使当前会话可以接收指定告警的通知信息。

REMOVE(name)

N/A

取消接收指定告警的通知信息。

REMOVEALL

N/A

从注册列表中删除此会话的所有告警。

SIGNAL(name, message)

N/A

产生指定名称的告警。

WAITANY(name OUT, message OUT, status OUT, timeout)

N/A

等待产生已注册的告警。

WAITONE(name, message OUT, status OUT, timeout)

N/A

等待产生指定的告警。

使用说明

REGISTER

当前会话可以接收指定告警的通知信息。

语法

REGISTER(name VARCHAR2) 

参数

参数名称

描述

name

被注册的告警名称。

示例

以下匿名代码块注册了一个名为alert_test的告警:

DECLARE
    v_name           VARCHAR2(30) := 'alert_test';
    v_msg            VARCHAR2(80);
    v_status         INTEGER;
    v_timeout        NUMBER(3) := 120;
BEGIN
    DBMS_ALERT.REGISTER(v_name);
    DBMS_OUTPUT.PUT_LINE('Registered for alert ' || v_name);
    DBMS_OUTPUT.PUT_LINE('Waiting for signal...');
    DBMS_ALERT.WAITONE(v_name,v_msg,v_status,v_timeout);
    DBMS_OUTPUT.PUT_LINE('Alert name   : ' || v_name);
    DBMS_OUTPUT.PUT_LINE('Alert msg    : ' || v_msg);
    DBMS_OUTPUT.PUT_LINE('Alert status : ' || v_status);
    DBMS_OUTPUT.PUT_LINE('Alert timeout: ' || v_timeout || ' seconds');
    DBMS_ALERT.REMOVE(v_name);
END;

执行代码块后的显示结果如下:

Registered for alert alert_test
Waiting for signal...

REMOVE

取消接收指定告警的通知信息。

语法

REMOVE(name VARCHAR2)

参数

参数名称

描述

name

被取消注册的告警名称。

REMOVEALL

从注册列表中删除此会话的所有告警。

语法

REMOVEALL

SIGNAL

产生指定名称的告警。

语法

SIGNAL(name VARCHAR2, message VARCHAR2)

参数

参数名称

描述

name

告警名称。

message

与告警相关的信息。

示例

以下匿名代码块发送了名称为alert_test的告警。

DECLARE
    v_name   VARCHAR2(30) := 'alert_test';
BEGIN
    DBMS_ALERT.SIGNAL(v_name,'This is the message from ' || v_name);
    DBMS_OUTPUT.PUT_LINE('Issued alert for ' || v_name);
END; 

执行代码块后显示的结果如下:

Issued alert for alert_test  

WAITANY

等待产生已注册的告警。

语法

WAITANY(name OUT VARCHAR2, message OUT VARCHAR2, status OUT INTEGER, timeout NUMBER)

参数

参数名称

描述

name

告警名称。

message

与告警相关的信息。

status

返回的状态码。

  • 0:产生告警。

  • 1:告警超时。

timeout

等待产生告警的时间。单位:秒。

示例

  1. 以下匿名代码块使用存储过程WAITANY来接收命名为alert_test或any_alert的告警:

    DECLARE
        v_name           VARCHAR2(30);
        v_msg            VARCHAR2(80);
        v_status         INTEGER;
        v_timeout        NUMBER(3) := 120;
    BEGIN
        DBMS_ALERT.REGISTER('alert_test');
        DBMS_ALERT.REGISTER('any_alert');
        DBMS_OUTPUT.PUT_LINE('Registered for alert alert_test and any_alert');
        DBMS_OUTPUT.PUT_LINE('Waiting for signal...');
        DBMS_ALERT.WAITANY(v_name,v_msg,v_status,v_timeout);
        DBMS_OUTPUT.PUT_LINE('Alert name   : ' || v_name);
        DBMS_OUTPUT.PUT_LINE('Alert msg    : ' || v_msg);
        DBMS_OUTPUT.PUT_LINE('Alert status : ' || v_status);
        DBMS_OUTPUT.PUT_LINE('Alert timeout: ' || v_timeout || ' seconds');
        DBMS_ALERT.REMOVEALL;
    END;   

    执行代码块显示的结果如下:

    Registered for alert alert_test and any_alert
    Waiting for signal...    
  2. 第二个会话中的匿名代码块为名为any_alert的告警发出的信号:

    DECLARE
        v_name   VARCHAR2(30) := 'any_alert';
    BEGIN
        DBMS_ALERT.SIGNAL(v_name,'This is the message from ' || v_name);
        DBMS_OUTPUT.PUT_LINE('Issued alert for ' || v_name);
    END;

    执行代码块后的显示结果如下:

    Issued alert for any_alert
  3. 控制流程返回第一个匿名代码块,然后执行剩余的代码:

    Registered for alert alert_test and any_alert
    Waiting for signal...
    Alert name   : any_alert
    Alert msg    : This is the message from any_alert
    Alert status : 0
    Alert timeout: 120 seconds

WAITONE

等待产生指定的告警。

语法

WAITONE(name VARCHAR2, message OUT VARCHAR2, status OUT INTEGER, timeout NUMBER)

参数

参数名称

描述

name

告警名称。

message

储过程SIGNAL发送的消息。

status

返回的状态码。

  • 0:产生告警。

  • 1:告警超时。

timeout

等待告警产生的时间。单位:秒。

示例

  1. 以下匿名代码块中,除使用存储过程WAITONE接收名称为alert_test的告警外,其余地方和使用存储过程WAITANY的示例类似。

    DECLARE
        v_name           VARCHAR2(30) := 'alert_test';
        v_msg            VARCHAR2(80);
        v_status         INTEGER;
        v_timeout        NUMBER(3) := 120;
    BEGIN
        DBMS_ALERT.REGISTER(v_name);
        DBMS_OUTPUT.PUT_LINE('Registered for alert ' || v_name);
        DBMS_OUTPUT.PUT_LINE('Waiting for signal...');
        DBMS_ALERT.WAITONE(v_name,v_msg,v_status,v_timeout);
        DBMS_OUTPUT.PUT_LINE('Alert name   : ' || v_name);
        DBMS_OUTPUT.PUT_LINE('Alert msg    : ' || v_msg);
        DBMS_OUTPUT.PUT_LINE('Alert status : ' || v_status);
        DBMS_OUTPUT.PUT_LINE('Alert timeout: ' || v_timeout || ' seconds');
        DBMS_ALERT.REMOVE(v_name);
    END;

    执行代码块后显示的结果如下:

    Registered for alert alert_test
    Waiting for signal...

  2. 第二个会话中的一个匿名块发送名称alert_test的告警信号:

    DECLARE
        v_name   VARCHAR2(30) := 'alert_test';
    BEGIN
        DBMS_ALERT.SIGNAL(v_name,'This is the message from ' || v_name);
        DBMS_OUTPUT.PUT_LINE('Issued alert for ' || v_name);
    END;

    执行代码块后显示的结果如下:

    Issued alert for alert_test

  3. 第一个会话收到告警信息,控制流程返回到匿名代码块,再执行这个匿名代码块的剩余代码。

    Registered for alert alert_test
    Waiting for signal...
    Alert name   : alert_test
    Alert msg    : This is the message from alert_test
    Alert status : 0
    Alert timeout: 120 seconds

综合性示例

以下示例中,当表dept和emp发生改变时,您可以使用两个触发器发送告警信息。使用一个匿名代码块监听这些告警,并且当收到告警时,显示相关信息。

  1. 准备基础数据。

    CREATE TABLE dept (
        deptno          NUMBER(2) NOT NULL CONSTRAINT dept_pk PRIMARY KEY,
        dname           VARCHAR2(14) CONSTRAINT dept_dname_uq UNIQUE,
        loc             VARCHAR2(13)
    );
    
    CREATE TABLE emp (
        empno           NUMBER(4) NOT NULL CONSTRAINT emp_pk PRIMARY KEY,
        ename           VARCHAR2(10),
        job             VARCHAR2(9),
        mgr             NUMBER(4),
        hiredate        DATE,
        sal             NUMBER(7,2) CONSTRAINT emp_sal_ck CHECK (sal > 0),
        comm            NUMBER(7,2),
        deptno          NUMBER(2) CONSTRAINT emp_ref_dept_fk
                            REFERENCES dept(deptno)
    );
    
    GRANT ALL ON emp TO PUBLIC;
    GRANT ALL ON dept TO PUBLIC;
    
    INSERT INTO dept VALUES (10,'ACCOUNTING','NEW YORK');
    INSERT INTO dept VALUES (20,'RESEARCH','DALLAS');
    INSERT INTO dept VALUES (30,'SALES','CHICAGO');
    INSERT INTO dept VALUES (40,'OPERATIONS','BOSTON');
    
    INSERT INTO emp VALUES (7369,'SMITH','CLERK',7902,'17-DEC-80',800,NULL,20);
    INSERT INTO emp VALUES (7499,'ALLEN','SALESMAN',7698,'20-FEB-81',1600,300,30);
    INSERT INTO emp VALUES (7521,'WARD','SALESMAN',7698,'22-FEB-81',1250,500,30);
    INSERT INTO emp VALUES (7566,'JONES','MANAGER',7839,'02-APR-81',2975,NULL,20);
    INSERT INTO emp VALUES (7654,'MARTIN','SALESMAN',7698,'28-SEP-81',1250,1400,30);
    INSERT INTO emp VALUES (7698,'BLAKE','MANAGER',7839,'01-MAY-81',2850,NULL,30);
    INSERT INTO emp VALUES (7782,'CLARK','MANAGER',7839,'09-JUN-81',2450,NULL,10);
    
    CREATE USER mary IDENTIFIED BY password;
    CREATE USER john IDENTIFIED BY password;
  2. 执行如下语句,在dept和emp表上定义触发器。

    CREATE OR REPLACE TRIGGER dept_alert_trig
        AFTER INSERT OR UPDATE OR DELETE ON dept
    DECLARE
        v_action        VARCHAR2(25);
    BEGIN
        IF INSERTING THEN
            v_action := ' added department(s) ';
        ELSIF UPDATING THEN
            v_action := ' updated department(s) ';
        ELSIF DELETING THEN
            v_action := ' deleted department(s) ';
        END IF;
        DBMS_ALERT.SIGNAL('dept_alert',USER || v_action || 'on ' ||
            SYSDATE);
    END;
    
    CREATE OR REPLACE TRIGGER emp_alert_trig
        AFTER INSERT OR UPDATE OR DELETE ON emp
    DECLARE
        v_action        VARCHAR2(25);
    BEGIN
        IF INSERTING THEN
            v_action := ' added employee(s) ';
        ELSIF UPDATING THEN
            v_action := ' updated employee(s) ';
        ELSIF DELETING THEN
            v_action := ' deleted employee(s) ';
        END IF;
        DBMS_ALERT.SIGNAL('emp_alert',USER || v_action || 'on ' ||
            SYSDATE);
    END;
  3. 在一个会话中执行如下匿名代码块:

    DECLARE
        v_dept_alert     VARCHAR2(30) := 'dept_alert';
        v_emp_alert      VARCHAR2(30) := 'emp_alert';
        v_name           VARCHAR2(30);
        v_msg            VARCHAR2(80);
        v_status         INTEGER;
        v_timeout        NUMBER(3) := 60;
    BEGIN
        DBMS_ALERT.REGISTER(v_dept_alert);
        DBMS_ALERT.REGISTER(v_emp_alert);
        DBMS_OUTPUT.PUT_LINE('Registered for alerts dept_alert and emp_alert');
        DBMS_OUTPUT.PUT_LINE('Waiting for signal...');
        LOOP
            DBMS_ALERT.WAITANY(v_name,v_msg,v_status,v_timeout);
            EXIT WHEN v_status != 0;
            DBMS_OUTPUT.PUT_LINE('Alert name   : ' || v_name);
            DBMS_OUTPUT.PUT_LINE('Alert msg    : ' || v_msg);
            DBMS_OUTPUT.PUT_LINE('Alert status : ' || v_status);
            DBMS_OUTPUT.PUT_LINE('------------------------------------' ||
                '-------------------------');
        END LOOP;
        DBMS_OUTPUT.PUT_LINE('Alert status : ' || v_status);
        DBMS_ALERT.REMOVEALL;
    END;

    返回结果如下:

    Registered for alerts dept_alert and emp_alert
    Waiting for signal...
  4. 在其它会话中对表dept和emp进行更新操作。

    • 用户mary对dept表和emp表执行以下操作:

      INSERT INTO dept VALUES (50, 'FINANCE', 'CHICAG0');
      INSERT INTO emp (empno,ename,deptno) VALUES (9001,'J0NES',50);
      INSERT INTO emp (empno,ename,deptno) VALUES (9002,'ALICE',50);
    • 用户john对dept表执行以下操作:

      INSERT INTO dept VALUES (60,'HR','L0S ANGELES');
  5. 此时步骤3的会话将显示从触发器中接收告警信号的匿名代码块显示的输出内容。

    Registered for alerts dept_alert and emp_alert
    Waiting for signal...
    Alert name   : dept_alert
    Alert msg    : mary added department(s) on 25-OCT-07 16:41:01
    Alert status : 0
    -------------------------------------------------------------
    Alert name   : emp_alert
    Alert msg    : mary added employee(s) on 25-OCT-07 16:41:02
    Alert status : 0
    -------------------------------------------------------------
    Alert name   : dept_alert
    Alert msg    : john added department(s) on 25-OCT-07 16:41:22
    Alert status : 0
    -------------------------------------------------------------
    Alert status : 1