关于oracle中触发器触发时,报“表发生了变化,触发器或函数不能读它”错误
最近遇到了一个关于在触发器中操作本表时报“表发生了变化,触发器或函数不能读它”错误的
,问题查找各种博客知道。有了一些理解。下面总结一下:
1.在同一个事务中,触发器不能读取或更新触发语句的任何变异表也包括触发表本身,
这些限制约束适用于所有行级触发器.
2.但是可以使用自治事物,解决这个问题。
如:
create table tb_test
(
tid number primary key,
username varchar2(10),
pwd varchar2(10)
);
create or replace trigger tri_test
after update on tb_test
for each row
declare
v_ddd tb_test.username%type;
pragma autonomous_transaction;
begin
select username into v_ddd from tb_test where tid=:new.tid;
dbms_output.put_line(v_ddd);
commit;
end;
上面如果不用自治事物就会报“表发生了变化,触发器或函数不能读它”错误
但是上面很容易产生死锁的问题,如果在触发其中,对触发该触发器的记录进行update,或者delete
操作时,会发生死锁。如:
create or replace trigger tri_test
after update on tb_test
for each row
declare
v_ddd tb_test.username%type;
pragma autonomous_transaction;
begin
update tb_test set username='eee' where tid=:new.tid;
commit;
end;
update tb_test set username='111' where tid=1;
ORA-0006O:等待资源时检测到死锁
但是如果不是对触发该触发器的记录,做这些操作则不会报错。
原因如下:
update对锁的流程:
当sql发出一个update请求之后,数据库会对表中的每条记录加上U锁。
然后数据库会根据where条件,将符合条件的记录转换为X锁。
对不满足条件的记录释放U锁。
假设有A,B事务,发生下面情况,就会发生死锁。而这也解释了,为什么
如果在触发其中,对触发该触发器的记录进行update,或者delete
操作时,会发生死锁。而对其他记录进行进行update,或者delete操作时,没有发生死锁的现象。
1、执行A的查询的时候,数据库将所有的记录加上U锁,
然后将将不是c2的记录全部释放U锁。对满足条件的数据添加X锁。
此时,A事务还没有结束,A不会释放此时的X锁。
2、B查询的时候,B会对表中的所有记录添加U锁,
因为B查询要用到t_table这张表,B查询c1的时候,
满足条件给c1添加上X锁。执行c=2的时候,要给c2加U锁,
此时该记录被A添加了X锁。所以B查询需要等A释放的X锁,
才可以执行。此时B等待。B要等待A释放c2的X锁
3、A的阻塞释放之后,A要进行第二条查询。
这个时候A要对符合第二个查询条件的记录添加X锁。
当执行c1的时候,c1刚才被B添加了X锁。
所以此时A等待。A在等待B的U锁释放。