GoProg

 
Топ хэштегов


Архив

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

В стандартной версии PostgreSQL такой возможности нет, но она появилась в Postgres Pro Enterprise начиная с версии 9.6 . Это новшество приближает Postgres Pro к “крупным” СУБД таким как Oracle.

Хотя автономные транзакции всегда выполняются внутри другой транзакции, в один момент времени может быть активна только одна транзакция; остальные должны ждать завершения активной транзакции. Когда автономная транзакция запускается, её родительская транзакция приостанавливается и помещается в стек автономных транзакций. Когда автономная транзакция фиксируется или отменяется, родительская транзакция извлекается из стека и продолжается. Завершить родительскую транзакцию можно только после завершения всех вложенных в неё автономных транзакций.

В рамках отдельной родительской транзакции можно выполнить несколько автономных, как последовательных, так и вложенных. По умолчанию Postgres Pro позволяет выполнить одновременно до 100 автономных транзакций во всех сеансах. Это ограничение можно увеличить, изменив параметр конфигурации max_autonomous_transactions. Максимальный уровень вложенности ограничен значением 128 и не может быть изменен.

Правила видимости действуют так же, как и с независимыми транзакциями, выполняемыми через dblink. Автономные транзакции не видят эффекта действия родительской транзакции, как ещё не зафиксированной. Родительская транзакция может видеть эффект действия вложенных в неё автономных транзакций в зависимости от её уровня изоляции. Например, родительская транзакция с уровнем изоляции Read Committed будет видеть все изменения, вносимые автономными транзакциями. Однако если для родительской транзакции выбран уровень Repeatable Read, результат действия автономных транзакций не будет виден.

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

Для реализации автономных транзакций претерпели изменения операторы BEGIN/END/COMMIT/ROLLBACK, которые были расширены необязательным ключевым словом AUTONOMOUS:

BEGIN [AUTONOMOUS] [TRANSACTION] [уровень-изоляции]
END [AUTONOMOUS] [TRANSACTION]

Указывать ключевое слово AUTONOMOUS в предложении END TRANSACTION не обязательно. С автономными транзакциями возможно организовать несколько уровней вложенности, но транзакция верхнего уровня автономной быть не может. Для автономных транзакций допускаются следующие уровни изоляции: SERIALIZABLE, REPEATABLE READ, READ COMMITTED или READ UNCOMMITTED.

Для работы с автономными транзакциями был также расширен PL/pgSQL, ключевым словом AUTONOMOUS, которое используется совместно с BEGIN.

create or replace function mylog() returns boolean as $$
begin autonomous
  begin autonomous
    insert into log_table values ('new log',now());
  end;
  ...
  return true;
end;
$$ language plpgsql;

Более того в случае автономных транзакций можно улучшить механизм NOTIFY/LISTEN, в котором нотификация из транзакции будет отправлена только в случае ее успешного завершения. Переход на использование автономных транзакций позволяет избежать отката NOTIFY.

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

#AST #databases #pgsql #postgres #postgresql #sql #автономныетранзакции #базыданных #транзакции



Новый комментарий: