Trigger
如何使用 DBMS_ALERT 從 Oracle (10g R1) 觸發器實現程序間通信?
讓我先聲明一下,我根本不精通 Oracle,MS SQL 是的,但不是 Oracle;這就是我問這個的原因。
目前設置
- 在 Red Hat Ent 上執行的 Oracle 10g 第 1 版。3(不支持)
- 無法升級作業系統或數據庫
- 不能廣泛修改數據庫(最好是只讀的)
- 使用 Visual Studio 2013 和 .net 4.5 訪問 Oracle 的數據
- 使用 ODAP/ODP.NET 11.2 第 5 版(由於使用 Oracle 10g R1,不能更新)
- 使用 System.Data.Oracle 而不是 ODP.NET 類來避免文件膨脹
- 無法使用數據更改通知,因為 10g R1 不支持它
在目前設置下,我可以輕鬆連接到數據庫、發出 sql 語句和讀/寫數據。正在編寫的應用程序將用作 Oracle 數據庫和 MongoDB 之間的一種適配器或橋樑,其中只有幾個表用於將更改複製到 MongoDB。
目前的實現使用
DBMS_ALERT
並將triggers
事件傳遞到 .net 應用程序中,此時它將讀取數據、轉換數據並將其寫入 MongoDB。這是正在使用的範例觸發器
CREATE OR REPLACE TRIGGER EXAMPLE.TABLENAME_ALERT AFTER UPDATE OR INSERT OR DELETE ON EXAMPLE.TABLENAME FOR EACH ROW BEGIN IF INSERTING THEN DBMS_ALERT.SIGNAL('DATA_INSERTED', :new.data_id); DBMS_OUTPUT.PUT_LINE('INSERTED'); ELSIF UPDATING THEN DBMS_ALERT.SIGNAL('DATA_UPDATED', :old.data_id); DBMS_OUTPUT.PUT_LINE('UPDATED'); ELSIF DELETING THEN DBMS_ALERT.SIGNAL('DATA_DELETED', :old.data_id); DBMS_OUTPUT.PUT_LINE('DELETED'); END IF; END;
如果我發出以下 SQL 語句:
update EXAMPLE.TABLENAME set example_column = 'test' where data_id = 1; update EXAMPLE.TABLENAME set example_column = 'test' where data_id = 2; update EXAMPLE.TABLENAME set example_column = 'test' where data_id = 3;
結果是在數據庫輸出中獲得 3 個單獨的
DATA_UPDATED
信號和 3 個單獨的行。UPDATED
另一方面,如果我發布此聲明:update EXAMPLE.TABLENAME set example_column = 'test' where data_id <= 3;
我得到的結果是 1 個
DATA_UPDATED
信號,其中包含更新的最後一行的 id 和UPDATED
數據庫輸出中的 3 個單獨的行。我需要獲得所有 3 個信號。我的猜測是,因為
DBMS_ALERT.SIGNAL
在送出事務之前不會觸發,因此只會觸發當時最新的信號,並且單個批量更新/插入/刪除被認為是 1 個事務,那麼我將收到的只是來自數據庫的 1 個信號.有沒有一種方法可以讓每個觸發器多次呼叫
DBMA_ALERT.SIGNAL
以實際發送所有信號?或者也許有更好的方法來檢測外部應用程序對數據庫中數據的更改?編輯我知道這個實現有程式碼味道,但我的雙手被束縛,我必須使用我們擁有的東西並且不能真正改變任何東西。
這可以通過這種方式完成。我不太喜歡它,因為它不是很優雅,如果發生意外的事情看起來很脆弱。
--1)Create a table in the user's schema or another new schema if you want separation. CREATE TABLE DATA_AUDIT ( Primary_key RAW(16) default SYS_GUID() not null, Data_id Number(10), Action VARCHAR2(10), Date_created TIMESTAMP(6)DEFAULT CURRENT_TIMESTAMP); --add foreign key constraint for Data_id to the parent Table --add check constraint: Action in ('INSERT','UPDATE','DELETE'); --2) create a trigger on the parent table CREATE OR REPLACE TRIGGER TGR_PARENT_TABLE BEFORE INSERT OR UPDATE OR DELETE ON PARENT_TABLE FOR EACH ROW v_action DATA_AUDIT.action%type; BEGIN IF INSERTING THEN v_action := 'INSERT'; ELSIF DELETING THEN v_action := 'DELETE'; ELSIF UPDATING THEN v_action := 'UPDATE'; ELSE --raise an error for an unexpected event and log it RAISE; END IF; Insert into DATA_AUDIT(Primary_key,Data_id, Action,Date_created) VALUES (SYS_GUID(), :old.Data_id, v_action,CURRENT_TIMESTAMP); END; --3) create a trigger on DATA_AUDIT CREATE OR REPLACE TRIGGER TGR_DATA_AUDIT BEFORE INSERT ON DATA_AUDIT FOR EACH ROW BEGIN DBMS_ALERT.SIGNAL(:old.action, :old.data_id); END;