Транзакции внутри транзакции

18

Какое поведение будет отображать PostgreSQL, если, например, был вызван скрипт ниже

BEGIN;
SELECT * FROM foo;
INSERT INTO foo(name) VALUES ('bar');
BEGIN; <- The point of interest
END;

Будет ли PostgreSQL отбрасывать второе BEGINили будет неявно определено принятие, а затем запустить BEGIN ENDблок в конце как отдельную транзакцию?

Alex
источник

Ответы:

13

Вам потребуется так называемая «автономная транзакция» (функция, предоставляемая Oracle). На данный момент это невозможно в PostgreSQL. Тем не менее, вы можете использовать SAVEPOINT s:

BEGIN;
INSERT ...
SAVEPOINT a;
some error;
ROLLBACK TO SAVEPOINT a;
COMMIT;

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

В противном случае нет другого разумного решения на данный момент.

Ханс-Юрген Шениг
источник
13

Вы можете попробовать это сами:

ВНИМАНИЕ: транзакция уже выполняется

Он не запускает новую (под) транзакцию, поскольку вложенные транзакции не реализованы в PostgreSQL. (Вы можете использовать магию в pl/pgsqlфункции, например, которая имитирует это поведение.)

С PostgreSQL 11 можно подумать, что новые реальные хранимые процедуры и их способность обрабатывать транзакции сделают возможными вложенные транзакции. Однако, согласно документации , это не так:

В процедурах, вызываемых CALLкомандой, а также в блоках анонимного кода ( DOкоманда), можно завершать транзакции, используя команды COMMITи ROLLBACK. Новая транзакция запускается автоматически после завершения транзакции с использованием этих команд, поэтому отдельной команды START TRANSACTION не существует.

Dezso
источник
9

PostgreSQL не поддерживает суб-транзакции, но эта SAVEPOINTфункция может эффективно удовлетворить ваши потребности. Цитирование из документации Advanced слоя доступа к PG через обещания по Виталию Томилово на GitHub:

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

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

Точки сохранения могут использоваться для частичного отката на более раннюю точку в активной транзакции. Например, чтобы установить точку сохранения, а затем отменить эффекты всех команд, выполненных после ее установки:

BEGIN;
    INSERT INTO table1 VALUES (1);
    SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (2);
    ROLLBACK TO SAVEPOINT my_savepoint;
    INSERT INTO table1 VALUES (3);
COMMIT;

Вышеуказанная транзакция вставит значения 1 и 3, но не 2. См. SAVEPOINTДокументацию для получения дополнительной информации.

Амир Али Акбари
источник
0

Для Postgresql 9.5 или новее вы можете использовать динамические фоновые рабочие, предоставляемые расширением pg_background. Создает автономную транзакцию. Пожалуйста, обратитесь к странице GitHub расширения. Решение лучше, чем db_link. В PostgreSQL имеется полное руководство по поддержке автономных транзакций.

Щербак
источник