关于oracle中触发器触发时,报“表发生了变化,触发器或函数不能读它”错误

本文探讨了Oracle数据库中触发器使用过程中遇到的“表发生了变化,触发器或函数不能读它”的错误,并介绍了如何通过自治事务来解决这一问题。同时,文章分析了在触发器中对触发记录进行修改时产生死锁的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



关于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锁释放。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值