Транзакции и ACID

↑ 2.1 PostgreSQL: индексы, транзакции, оптимизация · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Основа надёжности данных; спрашивают, что именно гарантирует каждая буква и как это реализовано.

ACID

СвойствоСмыслКак обеспечивается
Atomicityвсё или ничегооткат транзакции, MVCC
Consistencyпереход из корректного состояния в корректноеограничения, триггеры, правила приложения
Isolationпараллельные транзакции не мешают друг другуMVCC, блокировки, уровни изоляции
Durabilityпосле COMMIT данные не теряютсяWAL + fsync, репликация

Управление

BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT;        -- или ROLLBACK;
 
SAVEPOINT sp1; ... ROLLBACK TO sp1; RELEASE sp1;   -- частичный откат
  • любой отдельный оператор вне BEGIN выполняется в неявной транзакции (autocommit);
  • в PostgreSQL DDL транзакционен: CREATE TABLE, ALTER TABLE можно откатить;
  • после ошибки транзакция переходит в состояние aborted, пока не будет ROLLBACK (или откат к savepoint);
  • внутри транзакции now() возвращает время начала, clock_timestamp() — текущее.

Долговечность и скорость

synchronous_commit = on (по умолчанию) ждёт fsync WAL. off ускоряет, но при сбое можно потерять последние транзакции (без повреждения БД). remote_write, remote_apply — для синхронной репликации.

Транзакции и приложение

  • держите транзакции короткими: длинные блокируют VACUUM, держат блокировки, раздувают таблицы;
  • не делайте сетевые вызовы (HTTP, очередь) внутри транзакции;
  • обрабатывайте retry при serialization failure (40001) и deadlock (40P01);
  • идемпотентность операций при повторах;
  • в .NET: TransactionScope, DbContext.Database.BeginTransaction, SaveChanges сам создаёт транзакцию;
  • распределённые транзакции (между сервисами): saga, outbox, а не 2PC.

Двухфазный коммит

PREPARE TRANSACTION / COMMIT PREPARED — для координаторов (XA). Требует осторожности: подвисшие prepared-транзакции блокируют VACUUM.

Идентификатор транзакции

xid 32-битный, с циклическим счётчиком: wraparound предотвращается VACUUM FREEZE. Мониторинг age(datfrozenxid).

Вопросы с ответами