BEGIN/COMMIT/ROLLBACK
Тема дорожной карты · PostgreSQL
Транзакции PostgreSQL управляются явно с помощью команд BEGIN, COMMIT и ROLLBACK, которые обрамляют единицу работы, удовлетворяющую свойствам ACID: все операторы внутри либо выполняются вместе, либо не сохраняются вовсе. Команда BEGIN открывает блок транзакции, после чего все DML-операторы (INSERT, UPDATE, DELETE) удерживаются в незафиксированном состоянии, видимом только текущему сеансу, вплоть до вызова COMMIT, который делает изменения постоянными. При возникновении ошибки или явном вызове ROLLBACK PostgreSQL отменяет все изменения, выполненные с момента BEGIN, возвращая реляционную базу данных в предшествующее согласованное состояние без каких-либо частичных записей. PostgreSQL также поддерживает SAVEPOINT и ROLLBACK TO SAVEPOINT для частичного отката внутри одной транзакции, что особенно полезно в сложных рабочих процессах оптимизации запросов и конвейерах пакетной обработки данных.
Как это работает
BEGIN/COMMIT/ROLLBACK оборачивают несколько операторов как одну атомарную единицу: BEGIN; ... ; COMMIT; (или ROLLBACK). ACID-гарантии: atomicity (всё или ничего), consistency (constraints выполнены), isolation (конкурентные txn выглядят последовательно на выбранном уровне), durability (committed = записано). Уровни изоляции: Read Committed (дефолт), Repeatable Read, Serializable (сильнейший, может требовать retry). Postgres использует MVCC: читатели не блокируют писателей и наоборот.
Когда применять
Оборачивайте multi-row бизнес-операции в транзакции — частичное состояние после крэша хуже, чем сбой. Serializable — для денежной логики, где два конкурентных update могут двойной счёт; иначе Read Committed достаточен и быстрее. SELECT ... FOR UPDATE — для явных row-локов. Savepoint (SAVEPOINT ...; ROLLBACK TO ...;) — для nested partial rollback внутри длинной транзакции.
Типичные ошибки
Ловушки BEGIN/COMMIT/ROLLBACK: долгие транзакции блокируют VACUUM (autovacuum не освобождает, пока snapshot жив — bloat растёт); idle-in-transaction соединения (баговый ORM не делает commit/rollback); Serializable повсюду без retry-обработки (получите криптичные 40001); медленный внешний IO (HTTP-вызовы) внутри транзакции (lock держится слишком долго). Ставьте idle_in_transaction_session_timeout.