Перейти к основному содержимому

Управление транзакциями

примечание

Эта страница переведена при помощи нейросети GigaChat.

В процедурах, вызываемых командой 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 между ними.

PL/pgSQL не поддерживает точки сохранения (SAVEPOINT/ROLLBACK TO SAVEPOINT/RELEASE SAVEPOINT команды). Типичные шаблоны использования точек сохранения могут быть заменены блоками с обработчиками исключений (см. раздел Раздел 41.6.8). Под капотом блок с обработчиком исключений формирует подпотранзакцию, что означает невозможность завершения транзакций внутри такого блока.

Особые соображения применимы к циклам курсоров. Рассмотрим этот пример:

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, а не построчно. Курсор все еще удаляется автоматически после цикла, поэтому это в основном незаметно для пользователя. Тем не менее следует помнить, что любые блокировки таблиц или записей, установленные запросом курсора, больше не будут сохраняться после первого COMMIT или ROLLBACK.

Команды управления транзакциями не допускаются в циклах с курсором, которыми управляют запросы, производящие не только чтение, но и модификацию данных (например, UPDATE ... RETURNING).