Итак, у меня есть две таблицы: JOBS и TASKS.
В таблице TASKS есть столбец TAKS_STATUS, в котором хранится последовательность состояний (например, «Отправлено», «Отправлено», «Авторизовано», «Завершено»).
В таблице JOBS есть столбец JOB_STATUS, который представляет собой сводку (то есть минимальное состояние) столбцов TASK_STATUS в таблице TASKS. Таблица 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 must always match the number of rows in TASKS table
? - person krokodilko   schedule 22.05.2015