5.11 同一事件激活两个触发器
问题
现在需要创建一个触发器,把SYSDATE的值插入LOCATIONS表的HIRE_DATE字段。但是这个表已经有一个BEFORE INSERT触发器,而你又不希望这两个触发器产生冲突。
解决方案
使用FOLLOWS子句可以保证触发器按顺序执行。下面的例子创建了两个触发器,它们会在employees表的before insert事件发生时同时执行。
首先创建的触发器会验证雇员的工资是否处于某个范围内:
CREATE OR REPLACE TRIGGER verify_emp_salary
BEFORE INSERT ON employees
FOR EACH ROW
DECLARE
v_min_sal jobs.min_salary%TYPE;
v_max_sal jobs.max_salary%TYPE;
BEGIN
SELECT min_salary, max_salary
INTO v_min_sal, v_max_sal
FROM JOBS
WHERE JOB_ID = :new.JOB_ID;
IF :new.salary > v_max_sal THEN
RAISE_APPLICATION_ERROR(-20901,
'You cannot give a salary greater than the max in this category');
ELSIF :new.salary < v_min_sal THEN
RAISE_APPLICATION_ERROR(-20902,
'You cannot give a salary less than the min in this category');
END IF;
END;
/
接下来创建的触发器会强行将雇用日期修改为当前日期:
CREATE or REPLACE TRIGGER populate_hire_date
BEFORE INSERT
ON employees
FOR EACH ROW
FOLLOWS verify_emp_salary
DECLARE
BEGIN
:new.hire_date := sysdate;
END;
/
因为记录没有插入数据库时,修改雇佣日期没有任何意义,所以你想先触发verify_emp_salary触发器。这里只需要在populate_hire_date触发器中添加一个follows子句就可以达到这个效果。
原理分析
Oracle 11g为ORACLE触发器引入了FOLLOWS子句,它用于指定触发器的执行顺序。FOLLOWS子句会指定在激活当前触发器之前,先执行哪个触发器。换句话说,如果创建触发器时指定了FOLLOWS子句,那么FOLLOWS子句的触发器就会在当前触发器执行之前先触发。因此,如果你在FOLLOWS子句中指定了一个不存在的触发器,就会收到一个编译错误。
注意 PRECEDES子句同样是Oracle 11g中引入。可以用这个子句指定与FOLLOWS子句对立的情况。如果指定PRECEDES而非FOLLOWS子句,那么当前的触发器就会优先于PRECEDES子句中指定的触发器先被触发。
默认情况下Oracle触发器的执行是无序的。过去没办法保证触发器的执行顺序。现在新引入的FOLLOWS子句可以帮助指定触发器的执行顺序。但是,一定要确保触发器之间不要互相依赖。因为这样做可能导致其中的一个触发器被丢弃。如果一个触发器依赖于另外一个触发器的成功执行,那么这个设计可以说相当糟糕,所以FOLLOWS子句只应该在没有依赖的情况下使用。