关于错误:"table is mutating, trigger/function may not see it

来源:互联网 发布:java 循环替换字符串 编辑:程序博客网 时间:2024/06/06 20:41

转载于:http://www.itpub.net/thread-1032067-1-1.html#

 

关于错误:"table is mutating, trigger/function may not see it"

关于错误:"ORA-04091: table is mutating, trigger/function may not see it"的分析

在写trigger的时候,经常会遇到这种情况
当在程序块中需要对trigger本表进行修改或查询的时候,系统会提示错误:  ORA-04091: table is mutating, trigger/function may not see it

关于这个错误,其实是由于对本表的操作造成的.ORACLE DB里默认在写TRIGGER的时候把本表锁死,不允许对其进行操作,也就是说这个错误是不能通过系统的手段解决的,只能改用一些其它的SQL来绕开它.
刚接触TRIGGER的时候会经常犯这样的错误,其中有大部分是可以通过:new和ld来解决的,这是新手在写trigger时最需要注意的问题之一.
但是还会有一定要对本表进行修改或查询操作的情况,不能避免.
在网上搜索过一些关于这个问题的解决方法,至今也没有从根本上找到解决方法.
有人曾提议说,可以写一个PROCEDURE对本表进行操作,在TRIGGER里直接调用.此方法我也试过,还是不能避免这个问题,也有其他人作了和我一样的测试,结果是一样的.
目前找到的最好的解决这个问题的方法还是通过改写SQL,把一个TRIGGER要完成的功能分解,通过增加一步或几步操作把这个问题绕过去.
可是这种方法一来浪费时间精力,二来,并不是所有问题都可以找到绕过去的方法.

所以一直为此而头疼.

前几天又看到有人发布这个问题的求助,看到之后也只摇头,表示无能为力.
所以在这里提出来,不知道在座的各位高手有没有哪位有这方面的经验心得,有好的解决办法共享一下,在下不胜感激!!
============
SQL> CREATE TABLE T(ID NUMBER(18),MC VARCHAR2(20),DT DATE);

表已创建。

SQL> CREATE OR REPLACE TRIGGER TR_T
  2  AFTER DELETE ON T
  3  FOR EACH ROW
  4  DECLARE V_COUNT NUMBER;
  5  --PRAGMA AUTONOMOUS_TRANSACTION;
  6  BEGIN
  7     INSERT INTO T VALUES(:OLD.ID,:OLD.MC,SYSDATE);
  8     COMMIT;
  9  END TR_DEL_CABLE;
10  /

触发器已创建

SQL> INSERT INTO T VALUES(1,'111111',SYSDATE);

已创建 1 行。

SQL> INSERT INTO T VALUES(2,'222222',SYSDATE);

已创建 1 行。

SQL> COMMIT;

提交完成。

SQL> SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;

        ID MC                   TO_CHAR(DT,'YYYYM
---------- -------------------- -----------------
         1 111111               20080802 11:07:36
         2 222222               20080802 11:07:43

SQL> DELETE FROM T WHERE ID=1;
DELETE FROM T WHERE ID=1
            *
第 1 行出现错误:
ORA-04091: 表 TEST.T 发生了变化, 触发器/函数不能读它
ORA-06512: 在 "TEST.TR_T", line 4
ORA-04088: 触发器 'TEST.TR_T' 执行过程中出错


SQL> SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;

        ID MC                   TO_CHAR(DT,'YYYYM
---------- -------------------- -----------------
         1 111111               20080802 11:07:36
         2 222222               20080802 11:07:43

SQL> CREATE OR REPLACE TRIGGER TR_T
  2  AFTER DELETE ON T
  3  FOR EACH ROW
  4  DECLARE V_COUNT NUMBER;
  5  PRAGMA AUTONOMOUS_TRANSACTION;
  6  BEGIN
  7     INSERT INTO T VALUES(:OLD.ID,:OLD.MC,SYSDATE);
  8     COMMIT;
  9  END TR_DEL_CABLE;
10  /

触发器已创建

SQL> DELETE FROM T WHERE ID=1;

已删除 1 行。

SQL> COMMIT;

提交完成。

SQL> SELECT ID,MC,TO_CHAR(DT,'YYYYMMDD HH24:MI:SS') FROM T;

        ID MC                   TO_CHAR(DT,'YYYYM
---------- -------------------- -----------------
         2 222222               20080802 11:07:43
         1 111111               20080802 11:08:32


__________________
msn:zhouwf0726@hotmail.commail:zhouwf0726@163.com

 

 

 

==============

注意慎用AUTONOMOUS_TRANSACTION。一个DML可能触发很多次触发器,因此产生了大量独立的事务,很容易产生死锁。

ASKTOM上对AUTONOMOUS_TRANSACTION的看法是:唯一的用途就是作审计日志,其他一概不该使用。

还有我在这里不止一次呼吁过的:取消触发器,把你的业务逻辑写到存储过程去。