понедельник, 27 сентября 2010 г.

Oracle savepoints

В Oracle есть замечательная возможность создавать так называемые savepoint'ы (точки сохранений). Savepoint создаётся в транзакции, например перед началом изменений, а затем, после каких-то действий (если возникла ошибка, например) можно откатить транзакцию частично (до savepoint'а).

Один из вариантов использования точек сохранения такой:

  savepoint A; -- объявление точки сохранения
  begin
    .. do something ..
  exception
    when others then
      rollback to A; -- откат транзакции до точки A
  end;

Конструкция очень удобная при пакетной обработке данных. Например, обрабатывая тысячи записей, если возникает ошибка в какой-то одной строке (блок .. do something ..), то эта строка не обрабатывается (её можно пометить для ручной обработки).

У точек сохранения есть несколько особенностей.

  1. Именование точек. В приведённом примере: A - это имя точки. Оно может совпадать с именами переменных или других идентификаторов. Т.е. имя точки относится только к точке. Откат можно сделать к точке только по имени точки (не по имени или значению переменной).
  2. Можно создавать вложенные точки сохранения. (Где-то я читал про ограничение до 32х уровней вложенности.)
  3. Точки глобальны в пределах транзакции. Это значит, что точку сохранения можно объявить в одном программном модуле (процедуре, пакете), а возврат к точке - в другом.
  4. При объявлении второй точки сохранения с именем, которое использовалось ранее для предыдущей точки, происходит переопределение точки сохранения (первая точка сохранения удаляется).

Из 3го и 4го пунктов следует, что при именовании точек сохранения надо соблюдать некие правила, иначе можно столкнуться с довольно распространённой проблемой.

Например, есть функция, которая создаёт точку, что-то делает, если всё нормально - возвращает результат, а если возникает ошибка, то делает откат до точки сохранения и возвращает null. Если при этом в вызывающем модуле создать точку сохранения с таким же именем, как и в вызываемой функции, то после вызова функции откат транзакции до дочки сохранения произойдёт не так, как этого ожидал программист.

Вывод напрашивается простой: чтобы не было проблем с использованием точек сохранения, нужно именовать точки уникально. Однако, в сложных системах, когда программного кода на pl/sql очень много, придумывать уникальные имена сложно. Можно именовать точки так же, как и называется процедура, но существует вероятность, что появится процедура с таким же именем, но в другом пакете. А если есть вероятность, то полагаться на случай нельзя.

Напрашивается решение, в котором можно было бы объявлять точки сохранения не задумываясь об их имени. Т.е. приведённый пример хочется привести к такому виду:

declare
  spn varchar2(32);
begin
  spn := make_savepoint;
  begin
    ..do_something..
  exception
    when others then
      rollback_to(spn);
  end;
end;

В следующей заметке я напишу, как такое сделать.

1 коммент.:

Анонимный комментирует...

Информация была полезна. Спасибо.

Отправить комментарий

.

.