Oracle中如何维护两个不同表的触发器执行依赖顺序?
跨表触发器执行顺序控制问题
已知在Oracle中,单表的多个触发器可使用FOLLOWS子句指定执行顺序,但当前存在两个不同表(emp与emp_1)及对应触发器:
-- 表1:
CREATE TABLE emp( empId number PRIMARY KEY, FirstName varchar2(20), LastName varchar2(20), Email varchar2(25), PhoneNo varchar2(25), Salary number(8) );
-- 表2:
CREATE TABLE emp_1( empId number PRIMARY KEY, FirstName varchar2(20), LastName varchar2(20), Email varchar2(25), PhoneNo varchar2(25), Salary number(8) );
emp表上的触发器:
CREATE OR replace TRIGGER TRIGGER_emp BEFORE INSERT OR AFTER UPDATE ON emp FOR EACH ROW BEGIN dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS SECOND -EXECUTED'); END; /
emp_1表上的触发器:
CREATE OR replace TRIGGER TRIGGER_emp1 BEFORE INSERT OR AFTER UPDATE ON emp_1 FOR EACH ROW BEGIN dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS FIRST -EXECUTED'); END; /
需求为让TRIGGER_emp1先执行,TRIGGER_emp后执行,请问在Oracle中是否可实现该顺序控制?
回答
Oracle本身不支持直接跨表控制不同表触发器的执行顺序,核心原因如下:
FOLLOWS/PRECEDES这类用于指定触发器顺序的子句,仅适用于**同一张表、同一触发时机(比如BEFORE INSERT)**的多个触发器之间,跨表场景完全不适用。- 不同表的触发器触发时机完全由你的DML操作顺序决定:你先执行对
emp_1的INSERT/UPDATE,TRIGGER_emp1就先执行;先操作emp,TRIGGER_emp就先触发。如果是在同一个事务中同时操作两张表,触发器的执行顺序严格对应DML语句的执行顺序。
要实现你要的顺序,有两种可行思路:
- 调整DML执行顺序:如果业务允许,直接在事务中先执行针对
emp_1的操作,再执行针对emp的操作,这样两个触发器就会按TRIGGER_emp1→TRIGGER_emp的顺序触发。 - 提取逻辑到存储过程:把
TRIGGER_emp1中的业务逻辑提取成独立的存储过程,比如PROC_EMP1_LOGIC,然后在TRIGGER_emp的开头调用这个存储过程。这样当操作emp表时,会先执行原TRIGGER_emp1的逻辑,再执行TRIGGER_emp本身的逻辑,间接实现顺序控制。示例代码如下:
-- 提取存储过程 CREATE OR REPLACE PROCEDURE PROC_EMP1_LOGIC(p_new emp_1%ROWTYPE) IS BEGIN dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS FIRST -EXECUTED'); -- 原TRIGGER_emp1的其他业务逻辑 END; / -- 修改TRIGGER_emp,先调用emp_1的触发器逻辑 CREATE OR replace TRIGGER TRIGGER_emp BEFORE INSERT OR AFTER UPDATE ON emp FOR EACH ROW BEGIN -- 映射emp的新数据到emp_1的行结构,调用共享逻辑 DECLARE v_emp1_row emp_1%ROWTYPE; BEGIN v_emp1_row.empId := :new.empId; v_emp1_row.FirstName := :new.FirstName; v_emp1_row.LastName := :new.LastName; v_emp1_row.Email := :new.Email; v_emp1_row.PhoneNo := :new.PhoneNo; v_emp1_row.Salary := :new.Salary; PROC_EMP1_LOGIC(v_emp1_row); END; -- 执行原TRIGGER_emp的逻辑 dbms_output.put_line ('MY EXECUTE ORDER FOR EMP IS SECOND -EXECUTED'); END; / -- 原TRIGGER_emp1改为调用共享存储过程 CREATE OR replace TRIGGER TRIGGER_emp1 BEFORE INSERT OR AFTER UPDATE ON emp_1 FOR EACH ROW BEGIN PROC_EMP1_LOGIC(:new); END; /
内容的提问来源于stack exchange,提问作者Prakshi
相关产品推荐
相关产品推荐

