1. 程式人生 > >關於ORA-04091異常的出現原因,以及解決方案

關於ORA-04091異常的出現原因,以及解決方案

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;

 

原文章連線:https://www.linuxidc.com/Linux/2013-07/87076.htm