Автономные транзакции на языке PL/SQL

Автономные транзакции языка PL/SQLОпределяя блок PL/SQL как автономную транзакцию, вы тем самым изолируете вы­полняемые в нем команды DML от контекста транзакции вызывающего кода. Этот блок определяется как независимая транзакция, начатая другой транзакцией, которая является главной.

В блоке автономной транзакции главная транзакция приостанавливается. Вы выполня­ете SQL-операции, затем производите их фиксацию или откат и возобновляете главную транзакцию (рис. 1).



 

Последовательность выполнения главной и вложенной (автономной) транзакций 

Рис. 1. Последовательность выполнения главной и вложенной (автономной) транзакций

 

Определение автономной транзакции

Определить блок PL/SQL как автономную транзакцию очень просто. Для этого до­статочно включить в раздел объявлений следующую директиву:

 

PRAGMA AUTONOMOUS_TRANSACTION;

Директива приказывает компилятору PL/SQL назначить блок PL/SQL как автономный (независимый). В контексте автономных транзакций автономным может быть объявлен любой из следующих блоков:

Директива AUTONOMOUS_TRANSACTlON может располагаться в любом места раздела объяв­лений блока PL/SQL. Однако лучше всего разместить ее перед определениями струк­тур данных, чтобы любому программисту сразу было ясно, что программа является анонимной транзакцией. Введение этой директивы — единственное изменение в коде PL/SQL для поддержки анонимных транзакций. Все остальное — команды COMMIT и ROLLBACK, а также команды DML — остается прежним. Автономная транзакция просто изменяет их область действия и видимость при выполнении в контексте автономной транзакции, и вы должны включить команду COMMIT или ROLLBACK в каждую программу автономной транзакции.

 

Правила и ограничения на использование автономных транзакций

Включить в программный код директиву AUTONOMOUS_TRANSACTION несложно, однако при ее использовании действует целый ряд правил и ограничений.

 

/* Файл в Сети: autondlock.sql */
PROCEDURE update_salary (dept_in IN NUMBER)
IS
   PRAGMA AUTONOMOUS_TRANSACTION;
   CURSOR myemps IS
      SELECT empno FROM emp WHERE deptno = dept_in FOR UPDATE NOWAIT;
   BEGIN
      FOR rec IN myemps LOOP
         UPDATE emp SET sal = sal * 2 WHERE empno = rec.empno;
      END LOOP;
      COMMIT;
   END;
   BEGIN
      UPDATE emp SET sal = sal * 2; update_salary (10);
   END;

 

Результат не радует:

 

ERROR at line 1:
ORA-00054: resource busy and acquire with NOWAIT specified

Одна директива не может определить как автономные все подпрограммы пакета или все методы объектного типа. Эту директиву нужно явно включать в каждую программу. Соответственно, на основании только спецификации пакета невозможно определить, какие из программ работают в режиме автономной транзакции.

 

Область видимости транзакций

После выполнения в автономной транзакции команд COMMIT или ROLLBACK изменения по умолчанию немедленно становятся видимыми в главной транзакции. А если вы предпочитаете скрыть их от последней? Да, изменения должны быть сохранены или отменены, но информация об этом не должна становиться доступной в главной тран­закции. Для этой цели используется следующая модификация команды SET TRANSACTION:

 

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

По умолчанию для транзакции устанавливается уровень изоляции READ COMMITTED, при котором зафиксированные изменения тут же становятся видимыми главной транзакции. Как обычно, команда SET TRANSACTION должна выполняться до начала транзакции (то есть перед первой командой SQL). Кроме того, данная установка влияет на весь сеанс, а не только на текущую программу. Сценарий autonserial.sql на сайте книги демонстрирует уровень изоляции SERIALIZABLE в действии.

 

 

В каких случаях следует применять автономные транзакции

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

 

Создание механизма автономного протоколирования

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

Но у такого журнала имеется один недостаток: операции записи в журнал становятся частью транзакции. И если будет выполнена команда ROLLBACK, из журнала может быть удалена часть записей об ошибках. Конечно, это нежелательно. Можно попытаться с помощью точек сохранения выполнить откат таким образом, чтобы записи журнала оставались нетронутыми, но это крайне неудобно. Автономные транзакции суще­ственно упрощают протоколирование ошибок, делают его более удобным и надежным. Допустим, таблица-журнал определена следующим образом:

 

/* Файл в Сети: log.pkg */
CREATE TABLE logtab (
   code INTEGER, text VARCHAR2(4000), created_on DATE, created_by VARCHAR2(100), changed_on DATE, changed_by VARCHAR2(100)
);

Таблица будет использоваться для хранения информации об ошибках (функции SQLCODE и SQLERRM), а также для протоколирования других событий, не связанных с ошибками.

Как пользоваться журналом? Прежде всего рассмотрим неправильное решение:

 

EXCEPTION
WHEN OTHERS THEN
DECLARE
   v_code PLS_INTEGER := SQLCODE;
   v_msg VARCHAR2(1000) := SQLERRM;
   BEGIN
      INSERT INTO logtab VALUES (
         v_code, v_msg, SYSDATE, USER, SYSDATE, USER);
   END;
END;

Другими словами, никогда не реализуйте механизм протоколирования в разделе ис­ключений и других разделах основного кода приложения. Все операции с таблицей- журналом должны выполняться на отдельном программном уровне (это называется инкапсуляцией). Для этого есть несколько важных причин:

Наш очень простой пакет протоколирования состоит всего из двух процедур:

 

PACKAGE log IS
PROCEDURE putline (code_in IN INTEGER, text_in IN VARCHAR2);
PROCEDURE saveline (code_in IN INTEGER, text_in IN VARCHAR2);
END;

Чем putline отличается от saveline? Процедура log.saveline является автономной транзакцией, тогда как log. putline просто вставляет строку в таблицу. Вот тело пакета:

 

/* Файл в Сети: log.pkg */
PACKAGE BODY log IS
   PROCEDURE putline (
      code_in IN INTEGER, text_in IN VARCHAR2)
   IS
   BEGIN
      INSERT INTO logtab VALUES ( code_in, text_in,
         SYSDATE,
         USER,
         SYSDATE,
         USER
      );
   END;

   PROCEDURE saveline (
      code_in IN INTEGER, text_in IN VARCHAR2)
   IS
      PRAGMA AUTONOMOUS_TRANSACTION;
   BEGIN
      putline (code_in, text_in);
      COMMIT;
      EXCEPTION WHEN OTHERS THEN ROLLBACK;
   END;
END;

 

Несколько замечаний по поводу реализации, которые помогут вам лучше понять про­исходящее:

При наличии описываемого пакета обработка ошибок значительно упрощается:

 

EXCEPTION
   WHEN OTHERS THEN
   log.saveline (SQLCODE, SQLERRM);
END;

Только и всего. Разработчикам не нужно задумываться о структуре таблицы журнала; более того, они могут вообще не знать, что запись производится в таблицу базы данных. А поскольку транзакция автономна, то что бы ни происходило в приложении — журнал останется в целости и сохранности.

 

Вас заинтересует / Intresting for you:

Управление приложениями PL/SQL...
Управление приложениями PL/SQL... 4651 просмотров Stas Belkov Thu, 16 Jul 2020, 06:20:48
Встроенные методы коллекций PL...
Встроенные методы коллекций PL... 14849 просмотров sepia Tue, 29 Oct 2019, 09:54:01
Символьные функции и аргументы...
Символьные функции и аргументы... 18588 просмотров Анатолий Wed, 23 May 2018, 18:54:01
Основы языка PL/SQL: использов...
Основы языка PL/SQL: использов... 4701 просмотров Ирина Светлова Tue, 06 Feb 2018, 14:04:03
Печать
Войдите чтобы комментировать

Myk аватар
Myk ответил в теме #9252 5 года 6 мес. назад
Очень хорошие примеры. Некоторые примеры работы с транзакциями были мне не известны! Спасибо!!
Borberd аватар
Borberd ответил в теме #9232 5 года 6 мес. назад
Автономные транзакции дают большие возможности программисту. Изучить PRAGMA нужно как следует для качественного кодинга!