sve*_*vit 6 oracle triggers ora-04091 mutating-table
我的桌子:
TableA (id number, state number)
TableB (id number, tableAId number, state number)
TableC (id number, tableBId number, state number)
Run Code Online (Sandbox Code Playgroud)
因此TableC中的项是TableB的子项,TableB中的项是TableA的子项.反之亦然 - TableA中的项是TableB的父项,TableB中的项是TableC的父项.
我想控制父项的状态......比方说,我们有这些数据:
TableA (id, state):
1, 40
TableB (id, tableAId, state):
1, 1, 40
2, 1, 60
TableC (id, tableBId, state):
1, 1, 40
2, 1, 50
3, 2, 60
4, 2, 70
Run Code Online (Sandbox Code Playgroud)
父母国家应该始终保持他孩子最小的状态.所以如果我们现在像这样更新TableC:
update TableC set state = 50 where Id = 1;
Run Code Online (Sandbox Code Playgroud)
我的触发器应该自动更新TableB(设置状态= 50,其中id = 1),然后更新TableA(设置状态= 50,其中id = 1)
我想用触发器(在表A,表B,表C上进行更新,插入,删除之后)执行此操作,以便在执行每个操作后执行以下步骤:
如何避免"改变表错误"?在此示例中是否可以节省使用自治事务?我看到一些意见,变异表错误表明应用程序的逻辑存在缺陷 - 这是真的吗?如何更改我的逻辑以防止此错误?
谢谢
编辑:感谢所有的好答案!
最后,我使用了触发器(感谢Vincent Malgrat,他指出了Tom Kyte的文章).
编辑:在REAL END中,我使用了存储过程并删除了触发器:)
Vin*_*rat 12
您已经注意到,使用触发器很难回答您的业务需求.原因是Oracle 可以为单个查询(并行DML)同时更新/插入具有多个线程的表.这意味着您的会话无法在更新发生时查询它更新的表.
如果你真的想用触发器执行此操作,则必须遵循Tom Kyte在本文中显示的那种逻辑.你可以看到它并不简单.
还有另一种更简单,更优雅,更易于维护的方法:使用程序.撤消对应用程序用户的更新/插入权限,并编写一组允许应用程序更新状态列的过程.
这些过程将锁定父行(以防止多个会话修改同一组行),并以高效,可读和易于维护的方式应用您的业务逻辑.
你不应该使用触发器来处理复杂的业务逻辑.将其移动到存储过程(PL/SQL包)或客户端代码.具有大量触发器的应用程序变得难以驾驭,因为您很快就会失去任何"行动序列"的感觉.
使用自治事务绝对不安全,仅将自治事务用于日志记录,跟踪,调试和审计.
阅读:http://www.oracle.com/technetwork/issue-archive/2008/08-sep/o58asktom-101055.html
在这里,您可以阅读如何在不使用自治事务时使用触发器来解决问题:http://www.procaseconsulting.com/learning/papers/200004-mutating-table.pdf