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在很多地方的作用也是無可替代,這裏先不加以詳細闡述。

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