• 2013年1月18日调试触发器“表发生了变化,触发器或函数不能读它”的出现原因,以及解决方案


    1、异常出现的场景.

    :在使用Hibernate做为项目持久层的情况下,需要对某一张表进行一个扩展,扩展操作便是在该表上创建一个触发器。将表中的数据读入到其他表中。

    SQL语句如下:

    drop table tr_table;   
      
        create table tr_table(  --触发器作用表   
        tab_id number primary key,   
        tab_name varchar2(30) NOT NULL  
        )   
      
        create table ts_table as select * from tr_table; --提供扩展功能的表   
                   
        --定义的触发器,在tr_table表插入和更新数据之后向ts_table表插入当前操作的信息行。   
        create trigger iu_table   
        after insert or update on tr_table   
        for each row   
        begin  
            insert into ts_table select * from tr_table t where t.tab_id = :new.tab_id;   
        end is_table;   
      
        --对tr_table执行插入操作,触发ts_table插入操作   
        insert into tr_table(tab_id,tab_name) values(1,'test');   
           
        --弹出错误信息提示   
        --ORA-04091:表tr_table发生了变化 触发器/函数不能读它   
        --ORA-06512: 在iu_table line 2   
        --ORA-04088: 触发器iu_table 执行过程中出错

     


     2、问题分析

    :在Oracle中执行DML语句的时候是需要显示进行提交操作的。当我们进行插入的时候,会触发触发器执行对触发器作用表和扩展表的种种操作,但是这个时候触发器和插入语句是在同一个事务管理中的,因此在插入语句没有被提交的情况下,我们无法对触发器作用表进行其他额外的操作。如果执行其他额外的操作则会抛出如上异常信息。


    3、解决方案

    :1,我们知道,出错的原因是因为触发器和DML语句在同一事务管理中,所以方案一便是将触发器和DML语句分成两个单独的事务处理。这里可以使用Pragma autonomous_transaction; 告诉Oracle触发器是自定义事务处理。

    SQL语句如下:


          create trigger iu_table   
        after insert or update on tr_table   
        for each row   
        declare  --这里是关键的地方,在变量申明的地方,指定自定义事务处理。   
        pragma autonomous_transaction;    
        begin  
            insert into ts_table select * from tr_table t where t.tab_id = :new.tab_id;   
        --这里需要显示提交事务   
            commit;   
        end iu_table;

       :2,在Oracle Trigger中有:new,:old两个特殊变量,当触发器为行级触发器的时候,触发器就会提供new和old两个保存临时行数据的特殊变量,我们可以从俩个特殊的变量中取出数据执行扩张表的DML操作。

    SQL语句如下:

       

     create trigger iu_table   
        after insert on tr_table   
        for each row   
        begin  
            insert into ts_table(tab_id,tab_name) values(:new.tab_id,:new.tab_name);   
            --这里需要注意,要知道不同的触发类型其特殊变量:new和:old保存的值的区别。   
            --commit; 注意使用方案二,这里不能显示的进行提交操作操作,trigger中在没有声明自定义事务管理的时候,不能执行显示提交。   
        end iu_table;

    如果您觉得文章有用,也可以给水发个微信小额红包鼓励鼓励!!!

  • 相关阅读:
    JAVA中如何正确的用String转Date
    Windows搭建测试RabbitMq遇到的问题
    使用mysql innodb 使用5.7的json类型遇到的坑和解决办法
    Eclipse快捷键 10个最有用的快捷键
    python数据类型:序列(字符串,元组,列表,字典)
    mysql建表以及列属性
    mysql中的union用法以及子查询综合应用
    一道很好的mysql面试练习题,having综合应用
    mysql常用语句练习-基于ecshop2.7.3数据库(1)
    自定义MVC框架之工具类-模型类
  • 原文地址:https://www.cnblogs.com/soundcode/p/5550374.html
Copyright © 2020-2023  润新知