作为审计/历史记录功能的一部分,我想使用AFTER UPDATE触发器或任何其他触发器来处理以下场景,请告诉我。 场景 -
我正在使用以下触发器,给出死锁场景。请建议解决此问题。
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 :(得分: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;
基表的额外更新既冗余又有问题,因为这会导致循环无限递归。
此外,您无法提交触发器。无论如何你都不想提交,这会破坏事务逻辑。 不提交允许主事务在一个漂亮的原子块中回滚历史表和主表。