Oracle编写army表BEFORE DELETE触发器触发表变化错误如何解决
问题原因分析
- 根本原因是Oracle的*变异表(mutating table)*限制:当某张表正在执行DML操作的行级触发器期间,不允许其他触发器/逻辑对该表进行读取或修改,否则就会抛出你遇到的错误。
- 具体到你的业务流程,整个调用链如下:
- 你执行
DELETE FROM army WHERE name = xxx,触发army表上的BEFORE DELETE行级触发器TRG_DELETE_SOLDIER - 该触发器执行
DELETE FROM soldier WHERE army_name = :old.name,删除关联的士兵记录 - 你提到
soldier表上已有更新对应军队人数的触发器,该触发器在删除士兵时会执行类似UPDATE army SET number_of_soldiers = number_of_soldiers -1 WHERE name = :old.army_name的逻辑,此时army表正处于行级触发器的执行过程中,属于变异状态,直接触发了Oracle的变异表校验 - 报错中关联
operates表是因为你给soldier_id到operates的外键设置了ON DELETE CASCADE,删除soldier记录时会自动级联删除operates的关联数据,该级联操作和soldier的更新人数触发器处于同一个事务调用链,Oracle的错误栈会把调用路径上涉及的表都列出来,并非你的触发器直接操作了operates表。
- 你执行
修复方案
- 方案1:调整
soldier表的更新人数触发器类型,将行级触发器改为复合触发器,在AFTER STATEMENT阶段再批量更新对应army的人数,避开army表的变异状态。 - 方案2:修改
army的删除触发器逻辑,用包变量/临时表先存储要删除的军队名称,改为AFTER DELETE语句级触发器再批量删除关联的soldier记录,避免在行级触发器操作关联表触发反向更新。 - 方案3:移除
soldier上的更新人数触发器,将number_of_soldiers改为通过视图动态聚合计算,或使用物化视图定时同步,从根源上避免跨表更新触发的变异表问题。
内容的提问来源于stack exchange,提问作者Mark
相关产品推荐
相关产品推荐

