Изоляция транзакций
Изоляция определяет поведение параллельных транзакций. Названия уровней стандартизированы, но конкретные гарантии PostgreSQL, MySQL/InnoDB, Oracle и других СУБД различаются.
Аномалии
- dirty read — чтение незакоммиченных данных;
- non-repeatable read — одна строка при повторном чтении изменилась;
- phantom read — повторный предикат вернул другой набор строк;
- lost update — результат одного изменения перезаписан другим;
- write skew — две транзакции меняют разные строки на основе общего условия и вместе нарушают правило.
Уровни стандарта
| Уровень | Dirty read | Non-repeatable read | Phantom |
|---|---|---|---|
| Read uncommitted | возможно | возможно | возможно |
| Read committed | нет | возможно | возможно |
| Repeatable read | нет | нет | по стандарту возможно |
| Serializable | нет | нет | нет |
Это минимальные гарантии стандарта, а не точное описание реализации. Например, уровень REPEATABLE READ может быть построен на snapshot isolation и предотвращать часть phantom reads, но все еще допускать write skew.
MVCC и блокировки
MVCC хранит версии строк и позволяет читателю видеть согласованный снимок без блокировки обычной записи. Но:
- старые версии надо очищать;
- долгие транзакции мешают очистке;
- снимок не предотвращает все конфликты записи;
- чтение «для изменения» обычно требует блокировки (
FOR UPDATE).
BEGIN;
SELECT state
FROM orders
WHERE id = 42
FOR UPDATE;
UPDATE orders
SET state = 'PAID'
WHERE id = 42;
COMMIT;Как выбирать уровень
- Сформулировать инвариант: что нельзя нарушить.
- Описать параллельный сценарий, а не только одиночный запрос.
- Проверить гарантии выбранной СУБД.
- Выбрать сочетание уровня, атомарного DML, ограничений и блокировок.
- Обработать deadlock/serialization failure как ожидаемый класс ошибок, если допустим retry.
flowchart LR A["Бизнес-инвариант"] --> B["Конкурентный сценарий"] B --> C["Уровень изоляции"] C --> D["Lock / версия / constraint"] D --> E["Retry и наблюдаемость"]
Связано: Грязное чтение, Repeatable read, Lost Update, Опасности использования read committed.
Вопросы
Чем isolation level отличается от блокировки? Уровень задает наблюдаемую гарантию, блокировка — один из механизмов ее достижения.
Предотвращает ли snapshot isolation все аномалии? Нет, возможен write skew.
Почему нельзя выбирать уровень только по таблице из учебника? Реализации дают разные усиленные гарантии и используют разные снимки/блокировки.
Что делать при serialization failure? Откатить транзакцию и, если операция безопасно повторяема, выполнить ограниченный retry с backoff.
Нужно ли ставить serializable везде? Нет: это может увеличить конфликты и retries; уровень выбирают по инварианту и нагрузке.