我想在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,但是遇到了问题。
这似乎是常见的事情。它是如何正常处理的?
答案 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(*)
作为建议的优化。