Транзакции и ACID
Объединяем несколько операций в одно неделимое целое и понимаем, что такое ACID.
Транзакция — группа операций, которые выполняются как единое целое: либо применяются все, либо не применяется ни одна.
Классический пример: перевод денег
Перевод со счёта на счёт — это два действия: списать у одного и зачислить другому. Если между ними случится сбой, деньги «испарятся»: списано, но не зачислено. Транзакция гарантирует, что либо оба действия выполнятся, либо ни одно.
BEGIN; -- начали транзакцию
UPDATE accounts SET balance = balance - 1000 WHERE id = 1; -- списали
UPDATE accounts SET balance = balance + 1000 WHERE id = 2; -- зачислили
COMMIT; -- зафиксировали оба изменения
Между BEGIN и COMMIT изменения видны только вам. После COMMIT они становятся постоянными и видны всем. Если до COMMIT что-то пошло не так, мы откатываемся.
ROLLBACK — отмена
ROLLBACK отменяет все изменения с начала транзакции, будто их не было. Это страховка от ошибок.
BEGIN;
DELETE FROM orders WHERE created_at < '2020-01-01';
-- Ой, удалили слишком много! Откатываем:
ROLLBACK;
-- Все удалённые строки вернулись на место
Принципы ACID
Надёжность транзакций описывают четырьмя свойствами — аббревиатура ACID. PostgreSQL соблюдает их по умолчанию.
| Свойство | Что гарантирует |
| Atomicity (атомарность) | транзакция применяется целиком или не применяется вовсе |
| Consistency (согласованность) | база переходит из одного корректного состояния в другое, ограничения соблюдаются |
| Isolation (изоляция) | параллельные транзакции не мешают друг другу |
| Durability (устойчивость) | после COMMIT данные сохранены, даже если сервер тут же отключится |
Точки сохранения (SAVEPOINT)
Внутри транзакции можно ставить промежуточные метки и откатываться частично, не отменяя всю транзакцию.
BEGIN;
INSERT INTO logs (msg) VALUES ('шаг 1');
SAVEPOINT after_first; -- метка
INSERT INTO logs (msg) VALUES ('шаг 2');
ROLLBACK TO after_first; -- отменили только шаг 2
COMMIT; -- шаг 1 сохранён, шаг 2 — нет
Когда транзакции особенно нужны
- Любые переводы и платежи — деньги нельзя потерять.
- Создание связанных записей: заказ + позиции заказа должны появиться вместе.
- Массовые обновления, где важна «всё или ничего».
В обычной автокоммит-сессии каждая отдельная команда — это уже мини-транзакция. Явные BEGIN/COMMIT нужны, когда несколько команд обязаны выполниться как одно целое.
Итог
- Транзакция (
BEGIN ... COMMIT) делает группу операций неделимой: всё или ничего. ROLLBACKотменяет изменения с начала транзакции;SAVEPOINTпозволяет откатиться частично.- ACID — атомарность, согласованность, изоляция, устойчивость; PostgreSQL соблюдает их по умолчанию.