В 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 коммент.:
Информация была полезна. Спасибо.
Отправить комментарий