触发不会释放锁

时间:2019-08-19 19:27:12

标签: oracle triggers locking

我正在开发一个项目,该项目将替换现有的旧项目。一方面,我从外部视图中获取数据,另一方面,我从现有的生产数据中获取数据。两个系统之间的数据本来应该是同步的,但是它们没有任何有意义的水平。在大多数情况下,这并不是一个大问题,因为我已尽可能地将它们合并。在某些情况下,行在员工ID上匹配,而在其他情况下,仅使用姓氏和生日。

外部视图数据始终具有两条不同的信息,一个员工ID和另一个标识符。生产数据将始终具有一个唯一的ID,即file_number。有时生产将具有外部视图键,但这是不正常的。这些键是两侧的主键,而不是姓氏和生日。

由于这是最后一个比较,因此导致了这个问题,因为我们有几个要求,在这些条件下,仅允许我们根据此条件加入,例如,当生产方中存在的员工在外部视图中获得条目时。由于姓氏和出生日期并没有特别的区别,因此我为这些记录创建了一个排除表,否则将导致问题但有效(例如双胞胎)。排除表从双方获取所有违规记录。

由于无法找到一种方法来限制这些重复记录会自动输入到排除表中(对数据输入的控制较差),因此我转向了触发器。

错误

  

错误报告-       SQL错误:ORA-04021:等待锁定对象时发生超时       ORA-06512:位于“ USER.EXCLUSION_TRG”的第4行       ORA-04088:执行触发器USER.EXCLUSION_TRG时出错       ORA-06512:位于“ USER.VIEW_DUPLICATE_TRG”的第4行       ORA-04088:执行触发器USER.VIEW_DUPLICATE_TRG时出错       04021. 00000-“等待锁定对象%s%s%s%s%s时发生超时”       *原因:等待锁定库对象时,发生超时。       *操作:稍后重试该操作。

VIEW表的第一个触发器

CREATE OR REPLACE TRIGGER VIEW_DUPLICATE_TRG
AFTER INSERT OR UPDATE ON VIEW_PERSON
BEGIN

INSERT INTO VIEW_EXCLUSION_PERSON (EMPLID, PRI, COMMENTS)
select  emplid, PRI, 'VIEW CREATED '||SYSDATE from (
select upper(CONVERT(last_name, 'US7ASCII')) LAST_NAME, birthdate,first_name,emplid, pri,  count(*) over (partition by upper(CONVERT(last_name, 'US7ASCII')), birthdate) duplicate_count from VIEW_PERSON 
) K where duplicate_count > 1 
and NOT EXISTS (select emplid from exclusion_person Z WHERE K.EMPLID=Z.EMPLID);
END;

产品表的第二个触发器

CREATE OR REPLACE TRIGGER PROD_DUPLICATE_TRG
AFTER INSERT OR UPDATE ON BACKGROUND_INFO
BEGIN
INSERT INTO EXCLUSION_PERSON (FILE_NUMBER, COMMENTS)
SELECT FILE_NUMBER, 'PROD CREATED '||SYSDATE 
FROM BACKGROUND_INFO
WHERE (SURNAME, BIRTHDATE) IN
    (SELECT SURNAME, BIRTHDATE
    FROM BACKGROUND_INFO
    GROUP BY SURNAME, BIRTHDATE
    HAVING COUNT(*) > 1
    )
    AND FILE_NUMBER NOT IN (SELECT FILE_NUMBER FROM exclusion_person WHERE FILE_NUMBER IS NOT NULL);
END;

排除表的第三次触发

CREATE OR REPLACE TRIGGER EXCLUSION_TRG
AFTER INSERT ON EXCLUSION_PERSON
DECLARE 
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
EXECUTE IMMEDIATE 'ALTER TRIGGER EXCLUSION_TRG DISABLE';

merge into EXCLUSION_PERSON E
using (select file_number, DECODE(TRIM(PRI), '99999999', NULL, PRI) PRI from administrative_info) A
on (E.PRI=A.PRI)
when matched then update set E.file_number = A.file_number, E.COMMENTS = E.COMMENTS||', MATCHED ON PRI ON '||SYSDATE
WHERE E.FILE_NUMBER IS NULL AND E.PRI IS NOT NULL AND A.PRI IS NOT NULL;

MERGE INTO VIEW_EXCLUSION_PERSON E
USING (SELECT FILE_NUMBER, EMPLID FROM VIEW_PERSON) P
ON (P.EMPLID = E.EMPLID)
WHEN MATCHED THEN UPDATE SET 
    E.FILE_NUMBER = P.FILE_NUMBER,
    E.COMMENTS = E.COMMENTS||' MATCHED FROM PERSON '||SYSDATE
WHERE E.FILE_NUMBER IS NULL AND E.EMPLID IS NOT NULL AND P.FILE_NUMBER IS NOT NULL;

EXECUTE IMMEDIATE 'ALTER TRIGGER VIEW_DUPLICATE_TRG DISABLE';

MERGE INTO VIEW_PERSON P
USING (SELECT FILE_NUMBER, EMPLID FROM EXCLUSION_PERSON ) E
ON (P.EMPLID = E.EMPLID)
WHEN MATCHED THEN UPDATE SET P.FILE_NUMBER = E.FILE_NUMBER
WHERE P.FILE_NUMBER IS NULL AND E.EMPLID IS NOT NULL AND E.FILE_NUMBER IS NOT NULL;

EXECUTE IMMEDIATE 'ALTER TRIGGER VIEW_DUPLICATE_TRG ENABLE';
EXECUTE IMMEDIATE 'ALTER TRIGGER EXCLUSION_TRG ENABLE';
END;

所以问题似乎在于,第一个触发器VIEW_DUPLICATER_TRG正在锁定某些内容,而在EXCLUSION_TRG尝试运行时未释放该锁定。当我去寻找这个%S%S%S%S%S对象时,我只是找不到它,而且我的代码都没有调用此对象。

1 个答案:

答案 0 :(得分:1)

主要问题在这里:

EXECUTE IMMEDIATE 'ALTER TRIGGER EXCLUSION_TRG DISABLE';

这将尝试在触发器本身正在执行时禁用触发器

这将永远无法进行:您无法在触发器执行时禁用它。因此,尝试从自己的执行中更改其状态将被阻止。

您可以通过以下方式看到它:

create table t (
  c1 int
);

create or replace trigger trg
after insert on t
declare
  pragma autonomous_transaction;
begin
  execute immediate 'alter trigger trg disable';
end;
/

insert into t values ( 1 );

insert将被卡住,等待尝试禁用触发器。但是触发器正在执行。所以你不能禁用它。 AAAAARGGGH!

这整个过程需要重新设计。理想情况下, 没有 任何触发器!