ПрограммированиеData Engineer

Опишите принципы использования транзакционной изоляции (isolation levels) в SQL и как выбрать правильный уровень изоляции для приложения. Приведите примеры аномалий для каждого уровня.

Проходите собеседования с ИИ помощником Hintsage

Ответ

Изоляция транзакций влияет на то, как одновременные транзакции видят изменения друг друга. Это важная часть ACID-свойств. В ANSI SQL четыре базовых уровня изоляции:

  • READ UNCOMMITTED — Видит даже незакоммиченные изменения других транзакций (грязные чтения, dirty reads).
  • READ COMMITTED — Видит только закоммиченные изменения; предотвращает грязные чтения, но допускает неповторимые чтения (non-repeatable reads).
  • REPEATABLE READ — Одни и те же данные в одной транзакции видятся неизменно. Избегают грязных и неповторимых чтений, но возможны фантомные чтения (phantom reads).
  • SERIALIZABLE — Самый строгий, транзакции полностью изолированы, как будто выполняются по очереди; устраняет все виды аномалий.

Выбор уровня зависит от требований приложения:

  • Для отчетности часто достаточно REPEATABLE READ или выше;
  • Для highload-систем оптимальный компромисс — READ COMMITTED;
  • Для финансов — SERIALIZABLE, несмотря на снижение производительности.

Пример:

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; BEGIN; -- Дальнейшие SELECT будут видеть "замороженные" значения

Вопрос с подвохом

"Гарантирует ли уровень REPEATABLE READ защиту от фантомных чтений в любой БД?"

Нет. В PostgreSQL и некоторых других СУБД уровень REPEATABLE READ предотвращает только грязные и неповторимые чтения, но не обязательно защищает от фантомных чтений. В MySQL/InnoDB REPEATABLE READ — по сути SERIALIZABLE, но в других СУБД — нет.

Пример:
-- В одной транзакции читаем SELECT * FROM orders WHERE amount > 100; -- В другой транзакции вставлено новое значение с amount > 100 и коммитится -- Первая транзакция при повторном SELECT увидит "фантомную" строку, если изоляция ниже SERIALIZABLE

Примеры реальных ошибок из-за незнания тонкостей темы


История

Финансовый сервис заблокировал только READ COMMITTED ради производительности — пользователь увидел сумму, которую уже изменил другой процесс, появились расхождения баланса.


История

В системе бронирования отелей происходили двойные бронирования одного и того же номера — транзакции не изолировали выгрузку актуальных броней, уровень был READ COMMITTED.


История

Переход c MySQL на PostgreSQL: разработчик привык, что REPEATABLE READ защищает от фантомов, но после миграции появились "зависшие" заказы, которых не ожидали увидеть при повторных запросах в одной и той же транзакции.