DB2触发器行锁定

时间:2014-02-11 21:57:02

标签: sql triggers db2

我想在DB2 10.1.2(Linux上运行的LUW)中创建一个触发器,当一个字段更新到某个值时,该表中的行数将用该值计算,以查看它是否与计数匹配在另一个表中,然后更新该表(例如,将任务状态汇总到作业状态)。表达它似乎很容易:

CREATE TRIGGER AUTHORED
  AFTER UPDATE OF TASK_STATUS ON TASK_TABLE
  REFERENCING NEW AS N FOR EACH ROW WHEN (TASK_STATUS = 'Completed')
    update JOB_TABLE set JOB_STATUS='Completed'
      where JOB_TABLE.ID = N.JOB_ID
        and JOB_TABLE.TOTAL_TASKS = (select count(*) from TASK_TABLE
          where TASK_TABLE.JOB_ID = N.JOB_ID
            and TASK_TABLE.TASK_STATUS = 'Completed')

不幸的是,似乎触发器的上下文和触发器的主体不在同一工作单元中,并且当您计算从触发更新本身锁定的行时会发生死锁。这是我执行触发更新后“db2pd -wlocks”的输出:

Locks being waited on :
AppHandl [nod-index] TranHdl    Lockname                   Type       Mode Conv Sts CoorEDU    AppName  AuthID   AppID
44248    [000-44248] 111        0200040E070000000000000052 RowLock    ..X       G   1385       perl     KJPIRES  10.0.15.139.38727.140201011731
14937    [000-14937] 15         0200040E070000000000000052 RowLock    .NS       W   1238       perl     KJPIRES  10.0.15.139.55287.140211231609

我尝试使用“with UR”作为内部计数,但是当我创建触发器时会明确忽略它(“SQL20159W由于语句上下文而忽略了隔离子句.SQLSTATE = 01652”)。

我也试过使用BEFORE和INSTEAD OF,但是遇到了问题。

这似乎是常见的事情。它是如何正常处理的?

2 个答案:

答案 0 :(得分:0)

我不认为它陷入僵局。首先,DB2有一个死锁检测器,如果有两个连接在不同资源上有锁等待另一个,DB2会杀死其中一个。我没有看到两个连接。

其次,您正在尝试根据定义触发器的表(TASK_TABLE)中的值(COUNT)更新另一个表(JOB_TABLE)

CREATE TRIGGER AUTHORED
 AFTER UPDATE OF TASK_STATUS ON TASK_TABLE
 REFERENCING NEW AS N
 FOR EACH ROW WHEN (TASK_STATUS = 'Completed')
  update JOB_TABLE
   set JOB_STATUS='Completed'
   where JOB_TABLE.ID = N.JOB_ID
   and JOB_TABLE.TOTAL_TASKS = (       -- Total tasks before or after the update?
    select count(*)
    from TASK_TABLE
    where TASK_TABLE.JOB_ID = N.JOB_ID
    and TASK_TABLE.TASK_STATUS = 'Completed'
   )

您是否在触发器之外运行更新。它有用吗,不是吗?

我认为事务正在修改未提交的行(update task_table),当您在触发器中发出select时,它会等待同一个表上的提交。实际上,事务不知道正在更新的行是否处于“已完成”状态,并且您有一个谓词来查找哪一个更新:和JOB_TABLE.TOTAL_TASKS = x,但当前行可能是此集合的一部分。

您要更新哪一个?当前更新之前或当前更新之后的JOB_TABLE.TOTAL_TASKS?最后,我不确定你为什么会对此有一个断言。

BTW,不要使用count(*)而是使用count(0)

答案 1 :(得分:0)

上面的触发器没有任何问题。我不知道,我的JOB_TABLE上的一个打开的交易非常出色。我跟踪它,做了回滚并完成了触发更新。

我将使用count(0)代替count(*)作为建议的优化。