Лекция 7. Транзакции
ACID
- A — Atomicity (Атомарность). Транзакция выполняется полностью или не выполняется совсем.
- C — Consistency (Согласованность). После завершения транзакции БД остаётся в согласованном состоянии, то есть не возникает нарушений ограничений целостности.
Ограничения целостности:
NOT NULLUNIQUEPRIMARY KEYFOREIGN KEYCHECK— проверка условий- Exclusion constraints — расширенные ограничения
- I — Isolation (Изоляция). Параллельные транзакции выполняются так, как если бы они были последовательными, предотвращая конфликты данных.
- D — Durability (Долговечность). После фиксации (
COMMIT) изменения остаются в базе данных, даже если система выйдет из строя.
Уровни изоляции транзакций
- Read Uncommitted — позволяет читать даже незавершённые изменения других транзакций. (Есть в стандарте SQL, но в PostgreSQL фактически работает как Read Committed.)
- Read Committed (по умолчанию в PostgreSQL) — транзакция видит только зафиксированные (
COMMIT-нутые) изменения других транзакций. - Repeatable Read — транзакция видит данные в том виде, в каком они были на момент её начала, даже если другие транзакции вносят изменения.
- Serializable — максимальный уровень изоляции. Гарантирует, что параллельные транзакции выполняются так, как если бы они шли последовательно.
Аномалии
- Потерянное обновление (Lost Update). Две транзакции читают одну и ту же строку, затем одна обновляет её, а после этого вторая тоже обновляет — не учитывая изменений первой.
- Грязное чтение (Dirty Read). Транзакция читает ещё не зафиксированные изменения, сделанные другой транзакцией.
- Неповторяющееся чтение (Non-Repeatable Read). Транзакция дважды читает одну и ту же строку и получает разные значения, потому что другая транзакция успела её изменить и закоммитить между чтениями.
- Фантомное чтение (Phantom Read). Транзакция дважды читает набор строк по одному и тому же условию, а в промежутке между чтениями вторая транзакция добавляет строки, удовлетворяющие этому условию (и фиксирует изменения). Тогда первая транзакция получает разные наборы строк.
Serializable
Уровень Serializable должен предотвращать вообще все аномалии. Это означает, что разработчику приложения не надо думать об одновременном выполнении: если транзакции выполняют корректные последовательности операторов, работая в одиночку, данные будут согласованы и при их одновременной работе.
Аномалии сериализации
- Циклическая зависимость данных (Write Skew).
Почему именно такие уровни в стандарте?
Разница между уровнями изоляции стандарта объясняется как раз количеством необходимых блокировок:
- Транзакция блокирует изменяемые строки от изменения, но не от чтения → Read Uncommitted.
- Транзакция блокирует изменяемые строки и от чтения, и от изменения → Read Committed.
- Транзакция блокирует и читаемые, и изменяемые строки и от чтения, и от изменения → Repeatable Read.
- С Serializable проблема: невозможно заблокировать строку, которой ещё нет. Из-за этого остаётся возможность фантомного чтения. Поэтому для реализации Serializable обычных блокировок не хватает — нужно блокировать не строки, а условия (предикаты). Такие блокировки и были названы предикатными.
Write-Ahead Logging (WAL)
WAL — стратегия, при которой все изменения данных сначала записываются в журнал (лог), и только потом применяются к основным файлам базы данных. Это даёт долговечность (Durability в ACID): даже если сервер упадёт, изменения можно восстановить по журналу.
Структура WAL-записи
- Header (24 байта)
- Page ID (8 байт)
- Old Data (размер страницы)
- New Data (размер страницы)
- Checksum (8 байт)
Ключевые параметры
fsync = on
synchronous_commit = on
wal_buffers = 64MB
synchronous_commit
on—COMMITдожидается, пока WAL гарантированно сброшен на диск (максимальная надёжность).off—COMMITвозвращается сразу; данные могут быть потеряны при крахе (но БД останется консистентной).local— ждём fsync только локально (без подтверждения реплик).remote_write— ждём, пока WAL дошёл до памяти standby-реплики.remote_apply— ждём, пока WAL применён на standby (самый строгий режим).
Checkpoint
Checkpoint — процесс, при котором все изменяемые данные из буферного кэша сбрасываются на диск, создавая согласованное состояние базы данных. После чекпоинта старые WAL-записи становятся не нужны для восстановления.