【问题标题】:2 triggers launching sametime2个触发器同时启动
【发布时间】:2014-09-18 12:24:09
【问题描述】:

我有两张桌子

user_salary

 -------------------------
 |   user_id |  salary_p |
 -------------------------
 |    1      |    100    |
 |    2      |    200    |
 -------------------------

user_p_salary

------------------------
|   user_id |  salary_c |
-------------------------
|    1      |    100    |
|    2      |    200    |
-------------------------

user_salary 是通过 UI 使用的,它有以下触发器:

 create or replace trigger t$user_salary_aiu
  after insert or update of salary_p 
  on user_salary
  for each row
begin
  update user_p_salary t
  set t.salary_c = :new.salary_p,
  where t.user_id = :new.user_id
end t$user_salary_aiu;

user_p_salary 通过集成获取数据,代码如下:

 create or replace trigger t$user_p_salary_aiu
  after insert or update of salary_c 
  on user_p_salary
  for each row
begin
  update user_salary t
  set t.salary_p = :new.salary_c,
  where t.user_id = :new.user_id
end t$user_p_salary_aiu;    

现在的问题是,如果其中一个表获取数据,那么它会执行触发器并更新另一个表中的数据。但是,另一个表上的触发器也会执行..这就像触发器的循环。

唯一的方法是使用 execute immediate 'alter triggername disable' 但这似乎根本不适用于触发器。有什么想法吗?

提前致谢:-)

【问题讨论】:

  • 我很惊讶您没有收到 ORA-04091 错误。你在使用自主交易吗?
  • 是的,我收到 ORA-04901 错误

标签: oracle plsql oracle11g plsqldeveloper


【解决方案1】:

ORA-04091 错误正是这里应该发生的。简单来说,你不能做你想做的事。想想看——你更新表#1,然后表#1 上的触发器更新表#2,其触发器更新表#1,其触发器更新表#2,一遍又一遍。这是一个触发循环,Oracle 不允许这种情况发生。规则是行触发器不能访问在同一事务中已更改(或“变异”)的表。有一些技术(特别是复合触发器)可以让您“解决”这个问题,但最好的方法是重新设计以消除这个问题。很抱歉成为坏消息的承担者。祝你好运。

【讨论】:

    【解决方案2】:

    如果工资不等于新值,为什么不只更新工资,例如

    create or replace trigger t$user_salary_aiu
      after insert or update of salary_p 
      on user_salary
      for each row
    begin
      update user_p_salary t
      set t.salary_c = :new.salary_p
      where t.user_id = :new.user_id
      and (   t.salary_c <> :new.salary_p
          or (t.salary_c is null and :new.salary_p is not null)
          or (t.salary_c is not null and :new.salary_p is null) );
    end t$user_salary_aiu;
    
    create or replace trigger t$user_p_salary_aiu
      after insert or update of salary_c 
      on user_p_salary
      for each row
    begin
      update user_salary t
      set t.salary_p = :new.salary_c
      where t.user_id = :new.user_id
      and (   t.salary_p <> :new.salary_c;
          or (t.salary_p is null and :new.salary_c is not null)
          or (t.salary_p is not null and :new.salary_c is null) );
    end t$user_p_salary_aiu;   
    

    注意:尽管文档的措辞是 dml_event_clause update of column 似乎意味着如果列包含在触发 UPDATE 语句中,即如果列被更新,即使它被更新为相同的值,触发器也会触发就是这样。

    【讨论】:

      【解决方案3】:

      如何为每个表添加一个名为 BY_TRIGGER 的列。

      对于触发器之外的更新或插入,您只需不指定此列。但是,当从触发器中更新或插入时,您传递的值为 1。

      此外,在每个 trigegr 中,检查 :new.BY_TRIGGER 是否为 1,如果是,则跳过插入/更新到另一个表。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-08-12
        • 1970-01-01
        • 1970-01-01
        • 2014-06-25
        • 1970-01-01
        • 1970-01-01
        • 2016-11-01
        相关资源
        最近更新 更多