1

我一直在努力让这个查询启动并运行,但一直遇到死胡同,我已经阅读了很多论坛,但我找不到我的问题的解决方案。我最初的错误是表突变错误,我知道 oracle 仍在忙于处理表,因此无法执行我的第二个任务。基本上我有一个名为 project_tbl 的表和另一个表,它是该表的副本,名为 proj_archive_tbl。我的逻辑是,当 project_tbl 中名为 proj_status 的列更改为已完成时,它必须将整行插入 proj_archive_tbl,然后将 project_tbl 中的 deleted_status 列更改为“X”。

我的第一次尝试是执行并插入 proj_archive_tbl 的触发器,然后更新 project_tbl delete_status = 'X' 但我收到突变错误。

现在我创建了 2 个触发器,一个用于在项目表上的状态更改为完成时将数据复制到存档表,另一个触发器在将新行插入 proj_archive_tbl 时,将项目 delete_status 更新为“X”但得到“等待时检测到死锁资源”。我试过用数组创建一个包,但我很挣扎,因为我是 oracle 的新手,并且还尝试遵循 asktom 建议、复合触发器和 antonomous_transactions 但都无济于事。这是代码,如果有人可以帮助我或以正确的方式指导我,将不胜感激:

create or replace 
trigger Arch_Proj_trigger
    after update of proj_status on project_tbl
    for each row
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
begin
if upper(:new.proj_status) = UPPER('completed') then
    insert into proj_archive_tbl 
        values (
          :old.proj_code,
          :old.proj_name,
          :old.cust_code,
          :old.proj_manager,
          :old.start_date,
          :old.end_date,
          :old.max_budget,
          :new.proj_status,
          :old.delete_status);
end if;
commit;

结尾;

create or replace 
trigger Mark_Proj_Deleted
after insert on proj_archive_tbl
for each row
DECLARE
PRAGMA AUTONOMOUS_TRANSACTION;
begin
    update project_tbl set delete_status = 'X' 
    where proj_code = :new.proj_code;
commit;

结尾;

我希望我使用的是正确的论坛并且提供了足够的信息。请帮忙!阿德里安

4

1 回答 1

2

这种方法行不通。以下是导致死锁的原因:

  1. 当您更新一行时project_tbl,您的事务将获得一个行锁并应用更改
  2. 然后您的触发器arch_proj_trigger在更新后触发并将一行插入表中proj_archive_tbl
  3. 插入proj_archive_tbl表会导致触发器触发mark_proj_deleted- 这无法更新行,project_tbl因为从更新状态时原始事务仍保持其行锁
  4. 第一个触发器在第二个触发器完成之前无法完成 - 但第二个触发器永远不会完成,因为原始更新语句正在阻止它。

我通常不提倡在触发器中使用这种应用程序逻辑 - 出于上述原因和其他原因。一般来说,如果您开始遇到死锁或突变问题,则该方法是错误的。

我的建议是使用 PL/SQL 过程来执行这种类型的数据操作,并且不允许对表进行直接更新语句。至少这样,您实现了所需的控件,并且一切都变得更加简单并且(更重要的是)在事务上是合理的。

于 2013-08-31T16:25:58.103 回答