我正在制作航班预订系统并尝试在将航班分配到航班之前验证飞机可用性,我正在使用Apex并使用触发器执行此操作。触发器在插入情况下工作但是在更新的情况下我收到了错误。
错误:
•ORA-04091: table FLIGHT is mutating, trigger/function may not see it ORA-06512: at
"VALIDATEPLANE", line 2 ORA-04088: error during execution of trigger 'VALIDATEPLANE'
守则:
create or replace trigger "VALIDATEPLANE"
before
insert or update on "FLIGHT"
for each row
begin
for index1 in(select * from FLIGHT)
loop
if :new.PLANE_NO = index1.PLANE_NO
then
if :new.DEPARTUAL_DATE <index1.DEPARTUAL_DATE
or :new.DEPARTUAL_DATE > index1.DEPARTUAL_DATE
then
if :new.ARRIVE_DATE<=index1.ARRIVE_DATE
then
:new.ARRIVE_DATE := (index1.ARRIVE_DATE+1) + (:new.ARRIVE_DATE -:new.DEPARTUAL_DATE);
:new.DEPARTUAL_DATE := index1.ARRIVE_DATE +1;
end if;
ELSIF :new.DEPARTUAL_DATE =index1.DEPARTUAL_DATE
then
:new.ARRIVE_DATE := (index1.ARRIVE_DATE+1) + (:new.ARRIVE_DATE -:new.DEPARTUAL_DATE);
:new.DEPARTUAL_DATE := index1.ARRIVE_DATE +1;
end if;
end if;
end loop;
end;
答案 0 :(得分:3)
触发器不是一个好工具。触发语句可以插入多行,它可以使用多个并行线程来插入。因此,数据库无法保证在插入期间返回一致的行集:数据库可以在字面上同时插入多行。为了保护您,数据库返回一个变异错误。
此处对于每个插入的行,您将逐行查询整个表格(Schlemiel the painter's algorithm的完美示例)。
通常,将复杂的业务规则放在触发器中是一个坏主意,因为:
如果你遇到一个变异错误并且坚持使用触发器,这里有一个你需要跳过的箍的例子:Avoiding mutating errors by Tom Kyte。
我建议你改用PL / SQL程序。它们更易于编码,读取和维护。它们可以逻辑地分组在一个非常独立的包中。您将更容易使用设置逻辑,逐行逻辑的性能提升可能是至关重要的。
答案 1 :(得分:0)
当您触发插入语句时,例如INSERT INTO TABLE VALUES ()
,您确定要插入一行。
但是当你UPDATE
或MERGE
时,BEFORE INSERT
触发器知道它只针对第一行触发。但实际上,它无法获得稳定的行集。尝试重新处理受影响的行集。
答案 2 :(得分:0)
您无法对已触发触发器的表执行DML操作。在这种情况下,您已在表FLIGHT上创建了触发器并从同一个表中获取数据,即FLIGHT。
插入操作正在运行,因为它是一个before触发器,并且没有触发在表中尚未创建的行上触发器的逻辑。如果它是后触发器,那么在插入操作期间也会遇到相同的错误。
一种解决方案可能是引入一个保存类似于FLIGHT表的记录的并行表,您可以从该表中选择数据以便在触发器中进行比较。您只能在此触发器内将数据插入该表。但你应该避免这样的解决方案。