当我在乘客桌上插入后尝试触发扳机时,我收到此错误。此触发器应该调用一个过程,该过程接受新插入值的两个参数,并基于它更新另一个表,即预订表。但是,我收到了这个错误:
ORA-04091: table AIRLINESYSTEM.PASSENGER is mutating, trigger/function may not see it
ORA-06512: at "AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE", line 11 ORA-06512: at
"AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE", line 15 ORA-06512: at
"AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE_T1", line 3 ORA-04088: error during execution of
trigger 'AIRLINESYSTEM.CALCULATE_FLIGHT_PRICE_T1' (Row 3)
我在SQL命令行中编写并测试了该过程,它运行正常。问题似乎与触发器有关。这是触发代码:
create or replace trigger "CALCULATE_FLIGHT_PRICE_T1"
AFTER
insert on "PASSENGER"
for each row
begin
CALCULATE_FLIGHT_PRICE(:NEW.BOOKING_ID);
end;
为什么触发器没有调用过程?
答案 0 :(得分:4)
您正在以不应该使用的方式使用数据库触发器。数据库触发器尝试读取当前正在修改的表。如果Oracle允许您这样做,那么您将执行脏读。 幸运的是,Oracle会警告您的行为,并且您可以修改您的设计。
最好的解决方案是创建API。一种程序,最好是一个包装,允许您按照您希望的方式插入乘客。在伪PL / SQL代码中:
procedure insert_passenger
( p_passenger_nr in number
, p_passenger_name in varchar2
, ...
, p_booking_id in number
, p_dob in number
)
is
begin
insert into passenger (...)
values
( p_passenger_nr
, p_passenger_name
, ...
, p_booking_id
, p_dob
);
calculate_flight_price
( p_booking_id
, p_dob
);
end insert_passenger;
/
现在调用此过程,而不是insert语句。而你的变异表问题将会消失。
如果您坚持使用数据库触发器,则需要避免使用游标c_passengers中的select语句。这没有任何意义:您刚刚在表乘客中插入一行并知道所有列值。然后调用calculate_flight_price来检索已知的列DOB。 只需在您的calculate_flight_price过程中添加一个参数P_DOB,并使用:new.dob调用它,如下所示:
create or replace trigger calculate_flight_price_t1
after insert on passenger
for each row
begin
calculate_flight_price
( :new.booking_id
, :new.dob
);
end;
答案 1 :(得分:1)
哦,天哪......你正在光标中尝试Dirty Read
。这是一个糟糕的设计。
如果允许脏读,它会返回错误的答案,但它也会返回表中从不存在的答案。在多用户数据库中,脏读可能是一个危险的功能。
这里的重点是脏读不是一个特征;相反,这是一种责任。在Oracle数据库中,它只是不需要。你可以获得脏读 - 无阻塞的所有优点 - 没有任何不正确的结果。
阅读"READ UNCOMMITTED isolation level"
上允许脏读的更多信息。它提供了基于标准的定义,允许非阻塞读取。
其他方式
您误用了触发器。我的意思是使用错误的触发器。
在表A中插入/更新一行,表A上的触发器(对于每一行)在表A上执行查询(通过程序)?? !!!
Oracle抛出ORA-04091,这是一种预期的正常行为,Oracle希望保护您自己,因为它保证每个语句都是原子的(即要么失败要么完全成功),并且每个语句都看到一致的视图数据
您希望查询(2)不会在(1)上看到插入的行。这将是矛盾的
解决方案: - 使用before
代替after
CREATE OR REPLACE TRIGGER SOMENAME
BEFORE INSERT OR UPDATE ON SOMETABLE