SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW DISABLE 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3) 5 END; 6 / 警告: 创建的触发器带有编译错误。 SQL> INSERT INTO T VALUES (2, 'B'); 1 2 已创建 1 行。 SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW DISABLE 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3); 5 END; 6 / 触发器已创建 SQL> INSERT INTO T VALUES (3, 'C'); 1 2 已创建 1 行。 SQL> ALTER TRIGGER TRI_T_3 ENABLE; 触发器已更改 SQL> INSERT INTO T VALUES (4, 'D'); 3 1 2 已创建 1 行。
11g中对于触发器部分有了一定的增强,主要表现在两个方面。一个是对触发器的触发顺序可以进行控制。另一个是可以定义一个复合触发器。
首先介绍一下触发器的顺序控制。
在11g以前,Oracle的文档上一直是这样描述的:Oracle是不会保证同种类型的触发器的触发先后顺序。不过在测试中发现,Oracle似乎是根据触发器建立时间的先后决定触发顺序的:
SQL> CREATE TABLE T (ID NUMBER, NAME VARCHAR2(30)); 表已创建。 SQL> CREATE OR REPLACE TRIGGER TRI_T_1 AFTER INSERT ON T 2 FOR EACH ROW 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(1); 5 END; 6 / 触发器已创建 SQL> CREATE OR REPLACE TRIGGER TRI_T_2 AFTER INSERT ON T 2 FOR EACH ROW 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(2); 5 END; 6 / 触发器已创建 SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3); 5 END; 6 / 触发器已创建 SQL> SET SERVEROUT ON SQL> INSERT INTO T VALUES (1, 'A'); 3 2 1 已创建 1 行。 SQL> INSERT INTO T SELECT ROWNUM, OBJECT_NAME FROM USER_OBJECTS; 3 2 1 3 2 1 3 2 1 3 2 1 已创建4行。
如果将TRI_T_2删除,并重写建立,则这个触发器会最先触发:
SQL> DROP TRIGGER TRI_T_2; 触发器已删除。 SQL> CREATE OR REPLACE TRIGGER TRI_T_2 AFTER INSERT ON T 2 FOR EACH ROW 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(2); 5 END; 6 / 触发器已创建 SQL> INSERT INTO T VALUES (2, 'B'); 2 3 1 已创建 1 行。
如果同一类的触发器在触发的时候需要按照某种顺序触发,那么仅靠触发器创建时间先后这个条件是无法确保顺序不会发生变化的。
11g触发器新增了FOLLOWS语句,使得触发器建立的过程中可以指定顺序:
SQL> CREATE TABLE T (ID NUMBER, NAME VARCHAR2(30)); 表已创建。 SQL> CREATE OR REPLACE TRIGGER TRI_T_1 AFTER INSERT ON T 2 FOR EACH ROW 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(1); 5 END; 6 / 触发器已创建 SQL> CREATE OR REPLACE TRIGGER TRI_T_2 AFTER INSERT ON T 2 FOR EACH ROW FOLLOWS TRI_T_1 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(2); 5 END; 6 / 触发器已创建 SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW FOLLOWS TRI_T_2 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3); 5 END; 6 / 触发器已创建 SQL> SET SERVEROUT ON SQL> INSERT INTO T VALUES (1, 'A'); 1 2 3 已创建 1 行。
Oracle除了增加了FOLLOWS语法,还可以在创建触发器的时候指定DISABLE/ENABLE。这对于没有把握触发器是否会成功编译的情况很有帮助:
SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW FOLLOWS TRI_T_2 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3) 5 END; 6 / 警告: 创建的触发器带有编译错误。 SQL> INSERT INTO T VALUES (2, 'B'); INSERT INTO T VALUES (2, 'B') *第 1 行出现错误: ORA-04098: 触发器 'YANGTK.TRI_T_3' 无效且未通过重新验证
如果触发器建立的时候报错,那么这个基表相应的操作都会由于触发器的错误是失败。11g可以在建立触发器的时候就指定DISABLE,避免上面的问题产生:
SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW DISABLE 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3) 5 END; 6 / 警告: 创建的触发器带有编译错误。 SQL> INSERT INTO T VALUES (2, 'B'); 1 2 已创建 1 行。
这样避免了触发器建立中出现的错误影响到基表的DML操作。在触发器编译成功后,就可以通过ENABLE来启动触发器了。
SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW DISABLE 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3) 5 END; 6 / 警告: 创建的触发器带有编译错误。 SQL> INSERT INTO T VALUES (2, 'B'); 1 2 已创建 1 行。 SQL> CREATE OR REPLACE TRIGGER TRI_T_3 AFTER INSERT ON T 2 FOR EACH ROW DISABLE 3 BEGIN 4 DBMS_OUTPUT.PUT_LINE(3); 5 END; 6 / 触发器已创建 SQL> INSERT INTO T VALUES (3, 'C'); 1 2 已创建 1 行。 SQL> ALTER TRIGGER TRI_T_3 ENABLE; 触发器已更改 SQL> INSERT INTO T VALUES (4, 'D'); 3 1 2 已创建 1 行。