2014-03-19 59 views
0

作爲審計/歷史記錄功能的一部分,我想使用AFTER UPDATE觸發器或任何其他觸發器來處理以下情形,請讓我知道。 方案 -Oracle中AFTER UPDATE觸發器中的死鎖場景

  1. 將有2個表 - 基表和歷史表
  2. 在基表中的第一個插入相同記錄的任何記錄的更新(更新)歷史上的表舊值。
  3. 使用基礎表中的新值更新記錄。

我正在使用以下觸發器,給出死鎖情況。請建議解決此問題。

create table Base_table(
SYMBOL_ID   NUMBER(9) primary key, 
SYMBOL_NAME   VARCHAR2(20) , 
PRICE   NUMBER(9) , 
VERSION    NUMBER(1) 
) 
organization index; 

create table base_table_hist(
ID    NUMBER(9) primary key, 
SYMBOL_ID   NUMBER(9) , 
SYMBOL_NAME   VARCHAR2(20) , 
PRICE    NUMBER(9),  
VERSION    NUMBER(1) , 
constraint other_symbolid foreign key(symbol_id) references test_symbol(symbol_id) 
) 
organization index; 
************************************************************ 

create or replace Trigger Symbol_Ver 
AFTER UPDATE ON Base_table 
REFERENCING NEW AS New OLD AS Old 
FOR EACH ROW 

DECLARE 
new_version number(5); 
--Pragma AUTONOMOUS_TRANSACTION; 
Sid number(9); 
begin 
    if (:New.symbol_id <> :Old.symbol_id) OR (:New.price <> :Old.price) then 


    new_version:= :Old.version+1; 

    --insert into history table 
    insert into base_table_hist (id, symbol_id, symbol_name,price,version) 
     values (symbol_seq.nextval, :OLD.symbol_id, :OLD.symbol_name, :OLD.price, :OLD.version); 
    commit; 
    DBMS_OUTPUT.put_line('new_version..'||new_version); 
end if; 

if (:New.symbol_id <> :Old.symbol_id) OR (:New.price <> :Old.price) then 
    update base_table set version=new_version where symbol_id=:Old.symbol_id; 
end if; 

end; 
+0

真的是一個僵局?不是一個突變的表錯誤,或資源不足(因爲觸發器會重複從它內部的recursove更新)? –

+0

顯示它的死鎖錯誤(ORA-00060)。爲避免反覆發生火災情況(如:New.version = Old.Version),則執行INSERT和UPDATE操作。 – SandeepS

+0

但是你還在發射一個額外的更新,這很醜,我很驚訝的作品。你爲什麼不調整版本(設置':new.version'),並在'before'觸發器中創建歷史記錄,而不是做額外的DML? –

回答

1

自治事務創建一個新的,獨立的交易。所以你用兩個事務更新同一行,導致死鎖。

這裏您不需要自主觸發器。事實上,你不想在觸發器中用DML觸摸基表。這總是有問題的。

幸運的是,在這裏你可以使用常規BEFORE觸發(因爲你要更新一個字段):

CREATE OR REPLACE TRIGGER Symbol_Ver 
    BEFORE UPDATE ON Base_table 
    FOR EACH ROW 
BEGIN 
    IF (:New.symbol_id <> :Old.symbol_id) OR (:New.price <> :Old.price) THEN 

     -- this will change the value in the row being updated 
     :new.version := :Old.version + 1; 

     --insert into history table 
     INSERT INTO base_table_hist 
     (id, symbol_id, symbol_name, price, version) 
     VALUES 
     (symbol_seq.nextval, :OLD.symbol_id, 
      :OLD.symbol_name, :OLD.price, :OLD.version); 
     -- COMMIT <-- don't commit in a trigger! 
     DBMS_OUTPUT.put_line('new_version..' || new_version); 
    END IF; 
END; 

基表上附加的更新將是冗餘和有問題的,因爲這將導致循環無限遞歸。

你也不能在觸發器中提交。無論如何你都不想承諾,這打破了交易邏輯。 不提交允許主事務在一個很好的原子塊中回滾歷史表和主表。