【问题标题】:How to avoid ORA-04091 error within a trigger如何避免触发器中的 ORA-04091 错误
【发布时间】:2012-04-26 00:25:50
【问题描述】:

我在表 A 上有一个更新后触发器(触发器 A),它可以对表 B 进行更改。

我在表 B 上还有一个更新后触发器(触发器 B),它不做任何更改,但查询表 A 以对非规范化进行一些健全性检查。

所以触发器 B 可以触发以下两种方式之一:

  1. 如果我直接更新表 B,或者
  2. 如果我更新表 A 并触发 A 触发,导致表 B 更新。

在情况 2 中,我得到一个 ORA-04091:表名正在变异,触发器/函数可能看不到它错误。这似乎是正确的。

我想在触发器 B 中检查表 A 是否“处于错误状态”并提前退出(在这种情况下不需要运行健全性检查)。

在我的触发器中测试它的最佳方法是什么?只需添加一个吞下异常的异常处理程序?还有比这更优雅的吗?

【问题讨论】:

    标签: oracle plsql mutating-table


    【解决方案1】:

    您可以让 A 上的触发器做一些事情来提醒 B 上的触发器它不需要触发。有各种希望为会话设置某种状态。最简单的方法是创建一个带有布尔变量 bypass_checks_on_b 的包,然后在 A 上执行 UPDATE 之前将其设置为 TRUE,在 UPDATE 完成后设置为 FALSE,然后然后在进行验证之前在 B 上的触发器中检查此变量的状态。您也可以对临时表或上下文执行类似的操作,而不是使用包。效率较低,您可能会解析 B 上的触发器内的调用堆栈,以查看 A 上的触发器是否在调用堆栈中,但这往往会相当难看。

    不过,我会对整个架构非常谨慎。当您发现 A 上的触发器导致 B 上的触发器触发想要查询 A 时,几乎总是这样的情况是您在触发器中放置了太多逻辑并且您会更好地移动将该逻辑放入可以调用的存储过程层,而不是应用程序执行直接插入或更新。当您将太多逻辑推入触发器时,您最终会得到一个非常难以理解的系统,因为从应用程序代码中看各种语句具有什么样的副作用并不明显。最后你会得到非常有状态的代码,根据调用者的不同,你有许多通过单个代码的路径。这几乎可以肯定意味着会有一些状态你不测试或不考虑你会发现你的代码做了一些意想不到的事情。在拥有大量状态和拥有大量副作用的代码库之间,您可以很快构建一个本质上不可维护的代码库。

    【讨论】:

    • 我完全同意,但事实就是这样。打包解决方案似乎可以解决问题,谢谢!
    猜你喜欢
    • 2018-11-30
    • 1970-01-01
    • 2013-05-13
    • 2011-08-13
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 2015-08-03
    相关资源
    最近更新 更多