2014-01-03 5 views
0

Я делаю систему бронирования рейсов и пытаюсь проверить наличие самолета, прежде чем назначать его на рейс, я использую Apex и делаю это с помощью триггера. Триггер работает в случае вставки, однако в случае обновления я получил ошибку.Ошибка во время запуска триггера

Ошибка:

•ORA-04091: table FLIGHT is mutating, trigger/function may not see it ORA-06512: at 
"VALIDATEPLANE", line 2 ORA-04088: error during execution of trigger 'VALIDATEPLANE' 

Кодекс:

create or replace trigger "VALIDATEPLANE" 
before 
insert or update on "FLIGHT" 
for each row 
begin 
    for index1 in(select * from FLIGHT) 
    loop 
     if :new.PLANE_NO = index1.PLANE_NO 
     then 
      if :new.DEPARTUAL_DATE <index1.DEPARTUAL_DATE 
       or :new.DEPARTUAL_DATE > index1.DEPARTUAL_DATE 
      then 
       if :new.ARRIVE_DATE<=index1.ARRIVE_DATE 
       then 
        :new.ARRIVE_DATE := (index1.ARRIVE_DATE+1) + (:new.ARRIVE_DATE -:new.DEPARTUAL_DATE); 
        :new.DEPARTUAL_DATE := index1.ARRIVE_DATE +1; 
       end if; 
      ELSIF :new.DEPARTUAL_DATE =index1.DEPARTUAL_DATE 
      then 
       :new.ARRIVE_DATE := (index1.ARRIVE_DATE+1) + (:new.ARRIVE_DATE -:new.DEPARTUAL_DATE); 
       :new.DEPARTUAL_DATE := index1.ARRIVE_DATE +1; 
      end if; 
     end if; 
    end loop; 
end; 

ответ

0

Когда огонь вставки заявление, например, для INSERT INTO TABLE VALUES() это очень уверен, что вы пытаетесь вставить одну единственную строку.

Но если вы UPDATE или MERGE, то BEFORE INSERT триггер знает, что он стреляет только для первой строки. Но на самом деле он не может получить стабильный набор строк. Попробуйте переработать на множестве затронутых строк.

+0

Это, вероятно, вызовет ту же ошибку здесь :) –

+0

@VincentMalgrat Спасибо за это. Мои плохие глаза, я изначально думал, что это проблема грязного чтения и ответа из моих архивов. Иногда в пятницу вечером я становлюсь частично слепым :) Теперь я полностью изменил свой ответ – SriniV

3

Триггеры не являются хорошим инструментом здесь. Оператор запуска может вставлять несколько строк, он может использовать несколько параллельных потоков для вставки. Таким образом, база данных не может гарантировать последовательный набор строк во время вставки: база данных может в буквальном смысле вставить несколько строк одновременно. Чтобы защитить вас, база данных возвращает мутирующую ошибку.

Плюс здесь для каждой вставленной строки вы запрашиваете всю таблицу подряд за строкой (прекрасный пример Schlemiel the painter's algorithm).

В общем, это плохая идея поставить сложные бизнес-правила в триггерах, потому что:

  • результирующий код фрагментируется (бизнес-правило отделена от фактической вставки)
  • , таким образом, он изменяет стандартное поведение DML скрытым способом
  • логика нескольких триггеров, взаимодействующих друг с другом, трудно предсказать и затрудняет диагностику ошибок
  • Вы не можете использовать логику набора в триггерах строк, поэтому большую часть времени код является субоптимальным.

Если вы столкнетесь с мутагенными ошибки и настаивают на использовании триггеров, вот пример вида обручи вам придется прыгать через: Avoiding mutating errors by Tom Kyte.

Я советую вам использовать процедуры PL/SQL вместо. Их легче кодировать, читать и поддерживать. Они могут быть логически сгруппированы в красивой автономной упаковке. Вы будете более легко использовать заданную логику, усиление производительности по строковой логике может иметь решающее значение.

+0

+1 Для лучшего ответа, чтобы избежать мутирующих триггеров. :) – SriniV

0

не может выполнять операции DML на столе, для которого триггер активировал. В этом случае вы создали триггер в таблице FLIGHT и выборку данных из той же таблицы, то есть FLIGHT.

Операция вставки работает, потому что она является перед триггером и не существует никакой логики запуска триггера в строке, которая еще не создана в таблице. Если это был после триггера, вы столкнулись бы с такой же ошибкой во время операции вставки.

Одним из решений может быть введение параллельной таблицы, содержащей записи, похожие на таблицу FLIGHT, и вы можете выбрать данные из этой таблицы для сравнения в триггере. Вы можете вставлять данные в эту таблицу внутри этого триггера.Но вы должны избегать таких решений.

+0

Я полностью против дублирующей таблицы как «REFERENCE» и дублирующих задач. Вы считаете это хорошим дизайном? – SriniV

+0

@realspirituals: даже я против, поэтому я написал «решение может быть», а не единственное решение. Очевидно, что это станет классическим примером репликации данных и против нормализации базы данных. – San

+0

:) Я согласен, что, как вы сказали, «Может быть» решением. Я бы предпочел вторую мысль Винсента, которая более выполнима и легко ремонтируется – SriniV

Смежные вопросы