我有以下过程,其中包含pragma autonomous_transaction子句。现在,在验证来的业务逻辑之后,在Java代码中调用此过程。在执行了这个proc之后,它从一些java东西开始......
create or replace procedure UPDATE_INSTRUMENT
is
pragma autonomous_transaction;
begin
begin
update abc
set AUTHSTATUS = p_AUTHSTATUS,
STATUS = p_STATUS,
USERID = p_USERID,
LASTUPDATED = TO_DATE(p_LASTUPDATED, 'DD/MM/YYYY'),
USERDATETIME = TO_DATE(p_USERDATETIME, 'DD/MM/YYYY')
where TRANSACNO = p_TRANSACNO;
commit;
end;
begin
update xyz
set AUTHSTATUS = p_AUTHSTATUS,
USERID = p_USERID,
AUTHDATE = TO_DATE(SYSDATE, 'DD/MM/YYYY'),
LASTUPDATED = TO_DATE(SYSDATE, 'DD/MM/YYYY'),
where TRANSACNO = p_TRANSACNO;
commit;
end;
end UPDATE_INSTRUMENT;
表'xyz'有三个触发器,其中1个在Insert上,2个在Before更新事件之前。
P.N: - 在调用此过程之前,表'xyz'未在任何地方更新或锁定。
我收到以下错误。
ORA-00060:等待资源时检测到死锁
ORA-06512:在“ADTTRG_xyz”,第277行
ORA-04088:执行触发器'ADTTRG_xyz'时出错
表abc正在正确更新,但无法更新表xyz。
请解释为什么会出现这种僵局。
“发生了多么僵局。”
当两个会话同时尝试更改公共资源(例如表或唯一索引)时,会发生死锁,这样两个会话都可以在没有其他提交的情况下提交。这始终是一个应用程序设计缺陷,因为死锁是复杂流程和执行不当的逻辑策略的结果。
这里有一些线索就是这种情况。
ORA-06512:在“ADTTRG_xyz”,第277行
首先,具有数百行代码的触发器是代码气味。这是触发器中的大量代码。似乎那里有竞争的机会。特别是......
表'xyz'有三个触发器,而... 2在更新前事件。
'xyz'表上有两个BEFORE UPDATE触发器,生成死锁的事件是'xyz'的更新。这可能不是巧合。
您必须调查这两个触发器并确定它们需要哪些表和索引,以便您可以发现它们是否处于争用状态。
pragma autonomous_transaction;
PL/SQL documentation说“如果一个自治事务试图访问主事务所持有的资源,就会发生死锁。”自治交易是另一种代码味道。自治交易的有效用例非常少;更常见的是,他们习惯于将糟糕的数据模型与提交内容纠缠在一起。
所以你有很多事情需要调查。 Oracle提供诊断来帮助解决此问题。
发生死锁时,Oracle会生成跟踪文件。该文件将写入OS目录。如果您不知道它在哪里,您可以查询V $ DIAG_INFO视图。 Find out more。跟踪文件将告诉您生成死锁的两个rowid;你可以使用dbms_rowid.rowid_object()
找出对象id并将其插入select object_name from all_objects where object_id = :oid;
。根据组织安排事项的方式,您可能无法访问tracefile目录,在这种情况下,您需要向DBA寻求帮助。
一旦你知道哪个表处于死锁状态,你就会知道你的应用程序逻辑中必须要改变什么。可能这是一个相当大的变化,因为你的代码有许多红色标志(长触发器体,同一事件上的两个触发器,自治事务)。祝好运!