В Oracle есть замечательная возможность создавать так называемые savepoint'ы (точки сохранений). Savepoint создаётся в транзакции, например перед началом изменений, а затем, после каких-то действий (если возникла ошибка, например) можно откатить транзакцию частично (до savepoint'а).
Один из вариантов использования точек сохранения такой:
  savepoint A; -- объявление точки сохранения
  begin
    .. do something ..
  exception
    when others then
      rollback to A; -- откат транзакции до точки A
  end;
Конструкция очень удобная при пакетной обработке данных. Например, обрабатывая тысячи записей, если возникает ошибка в какой-то одной строке (блок .. do something ..), то эта строка не обрабатывается (её можно пометить для ручной обработки).
У точек сохранения есть несколько особенностей.
- Именование точек. В приведённом примере: A - это имя точки. Оно
может совпадать с именами переменных или других идентификаторов. Т.е.
имя точки относится только к точке. Откат можно сделать к точке только по имени точки (не по имени или значению переменной).
 
- Можно создавать вложенные точки сохранения. (Где-то я читал про ограничение до 32х уровней вложенности.)
- Точки глобальны в пределах транзакции. Это значит, что точку сохранения можно объявить в одном программном модуле (процедуре, пакете), а возврат к точке - в другом.
- При объявлении второй точки сохранения с именем, которое
использовалось ранее для предыдущей точки, происходит переопределение
точки сохранения (первая точка сохранения удаляется).
 
Из 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 коммент.:
Информация была полезна. Спасибо.
Отправить комментарий