2014-03-19 1 views
0

감사/기록 기능의 일부로 AFTER UPDATE 트리거 또는 다른 트리거를 사용하여 다음 시나리오를 처리하려면 알려주십시오. 시나리오 -오라클의 AFTER UPDATE 트리거의 교착 상태 시나리오

  1. 이 것이 개 테이블 - 기본 테이블 1 삽입 동일한 레코드의 모든 기록의 갱신에
  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

정말 교착 상태입니까? mutuating table 오류가 아니거나 리소스가 부족합니다 (트리거가 반복 된 업데이트에서 반복적으로 실행되므로)? –

+0

데드락 오류 (ORA-00060)가 표시됩니다. 반복적으로 화재 조건이 (if : New.version = Old.Version)로 변경된 다음 INSERT 및 UPDATE 조작으로 변경되지 않도록하십시오. – SandeepS

+0

하지만 여전히 추한 업데이트를 해고하고 있으며, 나는 놀란 작품입니다. 왜 DML을하기보다는'before' 트리거로 버전을 조정하고 ('new.version'을 설정하는 것), 히스토리 레코드를 만드는 것이 아닌가? –

답변

1

자율 트랜잭션은 새로운 독립 트랜잭션을 생성합니다. 따라서 두 개의 트랜잭션으로 동일한 행을 업데이트하면 교착 상태가 발생합니다.

여기서 자율 트리거가 필요하지 않습니다. 사실 트리거에서는 DML을 사용하여 기본 테이블을 만지는 것을 원하지 않습니다. 항상 문제가 있습니다. 기본 테이블에 추가 갱신이가 이어질 것이기 때문에 중복과 문제가 모두 될 것

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; 

: (당신이 필드를 업데이트하고 있기 때문에)

다행히, 여기 당신은 정기적으로 BEFORE 트리거를 사용할 수 있습니다 순환 무한 재귀.

또한 트리거로 커밋 할 수 없습니다. 어쨌든 커밋하고 싶지 않다면, 이것은 트랜잭션 로직을 깨뜨린다. 커밋하지 않음을 사용하면 주 트랜잭션이 기록 테이블과 주 테이블을 하나의 멋진 원자 덩어리로 롤백 할 수 있습니다.