Firebird 2.5 коммит / откат (с использованием автономной транзакции) в цикле - PullRequest
1 голос
/ 08 февраля 2020

Мне нужно обработать записи в l oop хранимой процедуры, например:

create or alter procedure process_waiting_records
as
  declare   v_id                type of column my_table.id;
begin
  for
    select
      t.id
    from
      my_table t
    where
      (t.status = 'WAITING_TO_PROCESS')
    order by
      t.created_at
    into
      :v_id
  do
  begin
    execute procedure process_one_record(:v_id);
  end
end ^

Проблема в том, что при сбое выполнения process_one_record() (генерируется любое исключение), вся Набор модификаций будет откатываться от вызывающего кода.

Цель состоит в том, чтобы обработать все возможные записи, на данный момент мне все равно, если некоторые записи не могут быть обработаны, эти ошибочные записи будут в любом случае записаны в таблицу журнала (с использованием автономной транзакции). ).

Я собирался вызвать хранимую процедуру process_one_record() также в блоке автономных транзакций с предложением when any do (dummy code). Тем не менее, я думаю, что это не сработает, потому что эта неудачная транзакция не будет откатываться, а будет подтверждена (имеется в виду обработка topi c: Firebird 2.5 в автономной транзакции ).

Может кто-нибудь указать мне правильное направление, как решить эту проблему?

1 Ответ

1 голос
/ 08 февраля 2020

Для этого вам не нужны анонимные транзакции. Когда исключение выбрасывается из хранимой процедуры, эффекты этой хранимой процедуры автоматически отменяются. Если хранимая процедура содержит SUSPEND, отменяются только эффекты до последнего SUSPEND (воспринимайте это как точку сохранения). Для любых других форм отката транзакция должна быть явно отменена.

См. Также Точки сохранения и PSQL в справочнике по языку Firebird 2.5.

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

Внутренне используются автоматические c точки сохранения

  • отменить все действия в блоке BEGIN...END, где происходит исключение
  • отменить все действия, выполненные процедурой или триггером, или, в случае выбираемой процедуры, все выполненные действия с момента последнего SUSPEND, когда выполнение прекращается преждевременно из-за неперехваченной ошибки или исключения

Каждый PSQL блок обработки исключений также ограничен автоматическими c системными точками сохранения.

ПРИМЕЧАНИЕ : Блок BEGIN...END сам не создает автоматическую точку сохранения. Точка сохранения создается только в блоках, которые содержат оператор WHEN для обработки исключений.

В этом случае, поскольку эффекты одного process_one_record должны быть отменены, но не вся обработка в process_waiting_records, вам нужно разрешить исключение из process_one_record, но перехватить его для этого одиночного вызова процедуры.

Короче говоря, вам нужно сделать что-то вроде:

for select
  ...
do
begin
  execute procedure process_one_record(:v_id);
  when any do
  begin
    -- do nothing, last call to `process_one_record` was undone
  end
end
...