如何避免触发器内的ORA-04091错误

时间:2012-04-13 15:55:46

标签: oracle plsql mutating-table

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

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

因此触发器B可以通过以下两种方式之一触发:

  1. 如果我直接更新表B或
  2. 如果我更新表A和触发器 触发,导致表B更新。
  3. 在案例2中,我得到一个ORA-04091:表名是变异的,触发器/函数可能看不到错误。这似乎是正确的。

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

    在触发器内测试此功能的最佳方法是什么?只需添加一个吞下异常的异常处理程序?还有什么比较优雅的吗?

1 个答案:

答案 0 :(得分:2)

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

但是,我会对整个架构非常谨慎。如果你发现A上的触发器会导致B上的触发器发出想要查询A的触发器,那么你几乎总是会在触发器中放置过多的逻辑并且你会更好地服务于移动该逻辑进入可以调用的存储过程层而不是直接插入或更新的应用程序。当您将太多逻辑推入触发器时,您最终会得到一个非常难以理解的系统,因为从应用程序代码中查看各种语句会产生什么样的副作用并不明显。最终你会得到非常有状态的代码,你可以通过一段代码获得许多路径,具体取决于调用者。这几乎肯定意味着会有一些状态,你没有测试或没有想到你会发现你的代码在哪里发生了意想不到的事情。在拥有大量状态和具有大量副作用的代码库之间,您很快就可以构建基本上无法维护的代码库。