关于触发器对扩展表插入操作引发的违反主键的唯一约束条件

时间:2023-01-09 05:06:41

今天在写了一个行级update触发器,对表tab_a进行更新操作的时,触发触发器对扩展表tab_b做插入操作。遇到的问题不是一般的多。

在触发器的块部分中用了 insert into tab_a(col_a1)  select col_b1 from tab_b  where col_b1= :new.col_b1;

tab_a为触发器的扩展表,tab_b为触发器的作用表。触发器写完之后,编译成功,然后执行:update tab_b where col_b2=xxxx;

报错:“表发生了变化,触发器或函数不能读它”;


问题分析:

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


解决思路:

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

 create trigger  or replace tab_b_tri   

    after  update on tab_b  
    for each row   
    declare  --这里是关键的地方,在变量申明的地方,指定自定义事务处理。   
    pragma autonomous_transaction;    
    begin 

      insert into tab_a(col_a1)  select col_b1 from tab_b  where col_b1= :new.col_b1;--这里的:new.col_b1是update操作更新后的列值

    --这里需要显示提交事务   
        commit;  --在一般的触发器中是不允许有rollback和commit的存在的。这是属于自定义事物

end tab_b_tri  ;

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

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