Управление транзакциями
Эта страница переведена при помощи нейросети 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
).