четверг, 15 сентября 2011 г.

Немного об автономных транзакциях в Oracle

Вступление.
Многие, кому приходилось работать с Oracle RDBMS, сталкивались с автономными транзакциями, которые можно использовать для обеспечения дополнительной гибкости в пакетах на PL/SQL. Если кратко, то этот механизм позволяет в любой месте выполняемого кода начать транзакцию, независимую от текущей.

Например, наша программа обрабатывает данные и попутно ведет лог своих действий в специальную таблицу. В случае, если в ходе выполнения возникла исключительная ситуация, программа откатывает все изменения и завершает работу. Вполне естественно и логично, что лог мы ведем как раз для того, чтобы посмотреть на каком шаге случилась беда. Однако, как мы узнаем, что записалось в лог, если все изменения, в том числе и записи в нашу специальную таблицу, откатываются? Вот тут-то на помощь и приходят автономные транзакции. При их использовании запись в лог совершается  в рамках отдельной транзакции, инициируемой текущей. Теперь нам безразлично, как завершилась основная транзакция - новые записи в логе никуда не денутся.


Иллюзия.
Надо сказать, что в большинстве случаев автономные транзакции используются именно таким образом. И было замечено, что у многих (хоть и не у всех) возникает некоторая иллюзия в их отношении.

Иллюзия такова - "Автономная транзакция видит неподтвержденные данные основной транзакции, а вот все изменения, ей проводимые, выполняются уже независимо от воли основной".

Как и всякое заблуждение, это высказывание не лишено некой рациональной логики. Ведь иначе зачем нам вообще эти автономные транзакции, если мы из них не можем "заглянуть" в данные основной транзакции? Тем более, мы же пишем логи с помощью автономных транзакций, стало быть, действительно, что-то видим.

Данные в СУБД и переменные PL/SQL.
Всё дело в том, что связь между основной транзакцией и автономной действительно существует. Но осуществляется она не через данные СУБД, а переменные PL/SQL. Всю информацию для лога блок, помеченный как автономная транзакция, берет из переменных, которые, являясь частью выполняемой логики, не зависят от транзакций. Это же относится и к курсорным переменным, через которых можно передавать целые выборки.

Как видим, ничего сверхъестественного и хитромудрого здесь нет, всё просто, банально и очевидно(на то она и автономная!). Однако, описанное заблуждение может присутствовать даже у опытных разработчиков Oracle, потому что, если использовать автономные транзакции в качестве удобного инструмента для ведения логов, то вполне можно жить с этим заблуждением.


Пример из жизни.
Лично я расставил для себя эти точки над i уже сравнительно давно, однако на днях, не подумав, попался в эту удочку снова. Итак, что произошло?

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

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

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

3 комментария:

  1. Примерчик решения бы не постеснялся выложить:)

    ОтветитьУдалить
  2. и ещё:
    1. отключи ввод капчи для юзеров, оставляющих комментарии.
    2. заказываю статью про fetch'инг не строки (кортежа) а бОльшего количества данных

    ОтветитьУдалить
  3. Пост задумывался именно таким - без единой строчки кода. Дабы не превращать блог в справочник.

    ОтветитьУдалить