【发布时间】:2015-08-03 20:50:43
【问题描述】:
所以我有两个表:JOBS 和 TASKS。
TAKSS 表有一个 TAKS_STATUS 列,用于存储状态的进展(例如“提交”、“已提交”、“已授权”、“已完成”)。
JOBS 表有一个 JOB_STATUS 列,它是 TASKS 表中 TASK_STATUS 列的汇总(即最小状态)。 JOBS 表还有一个 TASK_COUNT 值,其中包含与作业关联的任务数。
作业可以有一个或多个任务:每个表中的 JOB_ID 链接它们。
在 DB2 中,我有一系列简单的触发器来汇总这种状态;这是中间的一个:
create or replace trigger JOB_AUTHORED
after update of TASK_STATUS on TASKS
referencing NEW as N
for each row
when (TASK_STATUS = 'Authored')
update JOBS
set JOB_STATUS = 'Authored'
where JOBS.JOB_ID = N.JOB_ID
and TASK_COUNT=(
select count(0) from TASKS
where TASKS.JOB_ID = N.JOB_ID
and TASKS.TASK_STATUS in ('Authored','Completed'))
这在 DB2 中可以正常工作,因为触发器与触发事件在同一个工作单元中运行,因此它可以看到工作单元未提交的更改,并且可以计算刚刚发生的 TASK_STATUS 更改而不会触发行锁。
这是 Oracle 中翻译后的触发器:
create or replace trigger JOB_AUTHORED
after update of TASK_STATUS on TASKS
for each row
when (NEW.TASK_STATUS = 'Authored')
BEGIN
update JOBS
set JOB_STATUS='Authored'
where JOBS.JOB_ID = :NEW.JOB_ID and TASK_COUNT=(
select count(0) from TASKS
where TASKS.JOB_ID = :NEW.JOB_ID
and TASKS.TASK_STATUS in ('Authored','Completed'));
END;
在 Oracle 中,这会失败:
ORA-04091: table MYSCHEMA.TASKS is mutating, trigger/function may not see it#012ORA-06512: at "MYSCHEMA.JOB_AUTHORED", line 1#012ORA-04088: error during execution of trigger 'MYSCHEMA.JOB_AUTHORED'#012] [query: UPDATE TASKS SET TASK_STATUS=:1 where TASK_ID=:2
显然,Oracle 的触发器不在同一上下文中运行,看不到未提交的触发更新,因此永远无法计算包括触发行在内的特定状态的任务数。
我想我可以将 AFTER 触发器更改为 INSTEAD OF 触发器并更新触发器内的 TASK_STATUS(以及 JOB_STATUS)(因此作业更新可以看到任务更新),但我会遇到同样的错误?也许不是第一个任务更新,但是如果触发程序在提交之前更新了一堆任务怎么办:当第二个任务更新时会发生什么?
我还考虑过删除触发器并让程序扫描活动作业以了解其任务的状态,但这似乎不优雅。
在 Oracle 中这样的最佳实践是什么?
【问题讨论】:
-
您能解释一下为什么将 JOBS.TASK_COUNT 与 TASKS 表中的当前行数进行比较吗?我可以想象由于某些原因(应用程序错误?有人直接在表中插入/删除了一些行?)JOBS 中的计数将与 TASKS 表中相关行的计数不匹配,并且表中的数据不是处于一致状态。在这种情况下,您的触发器将静默失败,并且不会给出预期的原因。您如何执行规则
JOBS.TASK_COUNT must always match the number of rows in TASKS table? -
我计算处于特定状态或更高状态的 TASKS 的数量,以查看它是否与 TASK_COUNT 匹配,从而知道所有 TASKS 都已到达特定点(在此示例中:已创建) .因此,再举个例子,假设创建了一个 Job,其中有 20 个处于 Submitting Status 的 TASKS,它们开始运行并经历各种状态。当第一个任务点击“已授权”时,此触发器会检查是否有 20 个任务处于“已授权”或“已完成”状态,以及是否有作业变为“已授权”状态。由于这是第一个“授权”任务,计数将为 1,因此不会更改作业。
-
当第 20 个任务达到“已授权”状态时,触发器的选择计数变为真并将作业的状态设置为“已授权”。此时,有些任务可能处于“已授权”状态,有些可能处于稍后状态(例如“已完成”)。触发器正好触发了 20 次,沿途计数从 1 到 20。如果某些任务在之前或之后进入“错误”状态,那么 Job 将永远不会进入“已授权”(另一个触发器会导致 Job 汇总到“错误”状态)。