|
Программирование >> Oracle
Автономные транзакции 1185 Как видите, после выполнения анонимного блока кажется, что обе строки вставлены в таблицу Т и зафиксированы. Это, однако, ошибочное представление. Строка, вставленная функцией, на самом деле еще не зафиксирована. Она - часть родительской, еще не завершенной транзакции. Выполняя откат, мы убеждаемся, что она исчезает, а вот строка, вставленная в автономной транзакции, остается. Итак, автономная транзакция начинается с первого за конструкцией PRAGMA ключевого слова BEGIN и действует в пределах соответствующего блока. Любые функции или процедуры, которые вызываются в автономной транзакции, триггеры, срабатывание которых она вызывает, и т.д. являются частью этой автономной транзакции, и выполненные ими изменения будут зафиксированы или отменены вместе с ней. Автономные транзакции могут быть вложенными - в автономной транзакции можно начать новую автономную транзакцию. Вложенные автономные транзакции обрабатываются точно так же, как родительская, - они начинаются с первого ключевого слова BEGIN, действуют вплоть до соответствующего ключевого слова END и полностью независим! от родительской транзакции. Единственное ограничение на глубину вложенности автономных транзакций задается параметром инициализации TRANSACTIONS, который определяет, сколько одновременных транзакций может поддерживать сервер. Обычно это значение равно количеству сеансов (SESSIONS), умноженному на 1,1; если планируется интенсивно использовать автономные транзакции, значение этого параметра должно быть увеличено. Область действия Под областью действия подразумевается возможность получать значения различных элементов базы данных. В данном случае нас интересуют четыре элемента. Рассмотрим поочередно области действия: переменных пакетов; установок/параметров сеанса; изменений в базе данных; блокировок. Переменные пакетов Автономная транзакция создает новый контекст транзакции, но не новый сеанс. Поэтому любые переменные, находящиеся в области действия (доступные) родительской и автономной транзакции, будут в них идентичны, поскольку присвоение значений переменным не входит в транзакцию (нельзя вернуть переменной PL/SQL прежнее значение). Поэтому автономная транзакция может не только читать переменные состояния родительской транзакции, но и изменять их, и эти изменения будут видимы в родительской транзакции. Это означает, что поскольку изменения значений переменных не фиксируются и не откатываются, эти изменения выпадают из области действия автономных транзакций и происходят так же, как и при отсутствии автономных транзакций. Чтобы продемонст- Глава 15 рировать это на простом примере, я создам пакет с глобальной переменной. Родительская транзакция (наш сеанс) будет устанавливать этой переменной определенное значение, а в автономной транзакции оно будет изменяться. Это изменение скажется на родительской транзакции: tkyte@TKYTE816> create or replace package global variables 2 as 3 x number; 4 end; Package created. tkyte@TKYTE816> begin 2 global variables.x := 5; 3 end; PL/SQL procedure successfully completed. tkyteeTKYTE816> declare 2 pragma autonomous transaction; 3 begin 4 global variables.x := 10; 5 commit; 6 end; PL/SQL procedure successfully completed. tkyte@TKYTE816> set serveroutput on tkyte@TKYTE816> exec dbms output.put line(global variables.x); 10 PL/SQL procedure successfully completed. Это изменение глобальной переменной автономной транзакцией останется в силе независимо от конечного результата (фиксации или отката) автономной транзакции. Установки/параметры сеанса Опять-таки, поскольку автономные транзакции создают новую транзакцию, а не новый сеанс, состояние сеанса в родительской транзакции будет таким же, как и в порожденной. Обе транзакции выполняются в одном сеансе, хотя и отдельно. Сеанс организуется при подключении приложения к базе данных. При выполнении автономной транзакции повторное подключение не выполняется - используется то же подключение и тот же сеанс. Поэтому любые изменения на уровне сеанса, выполненные в родительской транзакции, будут видимы в порожденной и, более того, если в порожденной транзакции выполняются изменения на уровне сеанса с помощью оператора lER SESSION, они повлияют и на родительскую транзакцию. Следует отметить, что оператор SET TRANSACTION, no определению работающий на уровне транзакции, влияет только на транзакцию, в которой выполнен. Так что, например, если в автономной транзакции выполнен оператор SET TRANSACTION USE ROLLBACK SEGMENT, то со- Автономные транзакции 1187 ответствующий сегмент отката будет задан только для автономной, но не для родительской транзакции. Оператор SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, выполненный в автономной транзакции, влияет только на эту транзакцию, а вот при выполнении оператора ALTER SESSION SET ISOLATION LEVEL=SERIALIZABLE изменится и уровень изолированности следующей транзакции на уровне родительской. Кроме того, родительская транзакция, работающая в режиме READ ONLY, может вызвать автономную транзакцию, изменяющую базу данных. Автономная транзакция в этом случае может изменять данные. Изменения в базе данных Теперь переходим к самому интересному - изменениям в базе данных. Здесь происходящее несколько затуманивается. Изменения в базе данных, выполненные, но еще не зафиксированные родительской транзакцией, невидим! в автономных транзакциях. Изменения, выполненные и зафиксированные в родительской транзакции, всегда видимы порожденным транзакциям. Изменения, выполненные в автономной транзакции, могут как видимо!, так и невидим! в родительской транзакции - это зависит от уровня ее изолированности. Однако вот в чем неясность происходящего. Я вполне четко заявил, что изменения, выполненные в родительской транзакции, невидимы для порожденной, но это еще не все. Для курсора, отрытого в порожденной автономной транзакции, эти незафиксированные изменения невидимы. Но вот курсор, открытый в родительской транзакции, при выборе из него данных в порожденной, позволяет получить эти измененные данные. Следующий пример демонстрирует, о чем идет речь. Создадим новую таблицу ЕМР (для прежней мы создали всевозможные средства проверки), а затем напишем пакет, который ее изменяет и выдает содержимое. В этом пакете мы создадим глобальный курсор, выбирающий данные из таблицы ЕМР. В пакете будет одна процедура, оформленная как автономная транзакция. Она выбирает данные из курсора и выдает результаты. Сначала эта процедура проверяет, открыт ли курсор, и, если - нет, открывает его. Это позволит продемонстрировать разницу в получаемых результатах, в зависимости от того, где был открыт курсор. Результирующее множество курсора всегда согласовано на момент его открытия с учетом того, в какой транзакции он был открыт: tkyte@TKYTE816> drop table emp; Tabledropped. tkyte@TKYTE816> create table emp as select * from scott.emp; Table created. tkyte@TKYTE816> create or replace package my pkg 2 as 4 procedure run; 6 end; Package created.
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |