Изоляция транзакций

Изоляция определяет поведение параллельных транзакций. Названия уровней стандартизированы, но конкретные гарантии PostgreSQL, MySQL/InnoDB, Oracle и других СУБД различаются.

Аномалии

  • dirty read — чтение незакоммиченных данных;
  • non-repeatable read — одна строка при повторном чтении изменилась;
  • phantom read — повторный предикат вернул другой набор строк;
  • lost update — результат одного изменения перезаписан другим;
  • write skew — две транзакции меняют разные строки на основе общего условия и вместе нарушают правило.

Уровни стандарта

УровеньDirty readNon-repeatable readPhantom
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;

Как выбирать уровень

  1. Сформулировать инвариант: что нельзя нарушить.
  2. Описать параллельный сценарий, а не только одиночный запрос.
  3. Проверить гарантии выбранной СУБД.
  4. Выбрать сочетание уровня, атомарного DML, ограничений и блокировок.
  5. Обработать 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; уровень выбирают по инварианту и нагрузке.