41.8. Управление транзакциями#
41.8. Управление транзакциями #
В процедурах, вызываемых командой CALL, а также в анонимных блоках кода (команда DO), можно завершить транзакции с помощью команд COMMIT и ROLLBACK. После завершения транзакции с использованием этих команд автоматически запускается новая транзакция, поэтому отдельной команды START TRANSACTION нет. (Обратите внимание, что команды BEGIN и END имеют разные значения в PL/pgSQL).
Вот простой пример:
CREATE PROCEDURE transaction_test1()
LANGUAGE plpgsql
AS $$
BEGIN
FOR i IN 0..9 LOOP
INSERT INTO test1 (a) VALUES (i);
IF i % 2 = 0 THEN
COMMIT;
ELSE
ROLLBACK;
END IF;
END LOOP;
END;
$$;
CALL transaction_test1();
Новая транзакция начинается с предустановленными характеристиками транзакции, такими как уровень изоляции транзакции. В случаях, когда транзакции коммитятся в цикле, может быть желательно автоматически начинать новые транзакции с теми же характеристиками, что и предыдущая. Команды COMMIT AND CHAIN и ROLLBACK AND CHAIN выполняют это.
Управление транзакциями возможно только в вызовах CALL или
DO на верхнем уровне или вложенных вызовах
CALL или DO без других
команд между ними. Например, если стек вызовов выглядит так:
CALL proc1() → CALL proc2()
→ CALL proc3(), то вторая и третья
процедуры могут выполнять действия по управлению транзакциями. Но если стек вызовов
выглядит так: CALL proc1() → SELECT
func2() → CALL proc3(), то последняя
процедура не может выполнять управление транзакциями из-за
наличия SELECT между ними.
Особые соображения применяются к циклам курсоров. Рассмотрим следующий пример:
CREATE PROCEDURE transaction_test2()
LANGUAGE plpgsql
AS $$
DECLARE
r RECORD;
BEGIN
FOR r IN SELECT * FROM test2 ORDER BY x LOOP
INSERT INTO test1 (a) VALUES (r.x);
COMMIT;
END LOOP;
END;
$$;
CALL transaction_test2();
Обычно курсоры автоматически закрываются при коммите транзакции.
Однако, курсор, созданный в рамках цикла, автоматически преобразуется в удерживаемый курсор при первой команде COMMIT или ROLLBACK. Это означает, что курсор полностью вычисляется при первой команде COMMIT или ROLLBACK, а не построчно. Курсор все еще автоматически удаляется после цикла, поэтому это в основном невидимо для пользователя.
Транзакционные команды не разрешены в циклах курсора, управляемых командами, которые не являются только для чтения (например, UPDATE ... RETURNING).
Транзакция не может быть завершена внутри блока с обработчиками исключений.