Вопрос 2 · Раздел 11

Какие уровни изоляции транзакций существуют?

Уровни изоляции определяют, насколько строго транзакции защищают друг друга от interference. Существует 4 уровня, от самого слабого к самому строгому:

Версии по языкам: English Russian Ukrainian

🟢 Junior Level

Уровни изоляции определяют, насколько строго транзакции защищают друг друга от interference. Существует 4 уровня, от самого слабого к самому строгому:

1. Read Uncommitted

Самый слабый уровень. Транзакция видит даже незафиксированные изменения других транзакций. Допускает все аномалии.

2. Read Committed

Транзакция видит только зафиксированные данные. Один и тот же запрос внутри транзакции может вернуть разные результаты.

3. Repeatable Read

Гарантирует, что данные, прочитанные один раз, не изменятся до конца транзакции.

4. Serializable

Самый строгий уровень. Транзакции выполняются так, будто параллелизма не существует вовсе.

Таблица аномалий

Уровень Грязное чтение Неповторяющееся чтение Фантомное чтение
Read Uncommitted Возможно Возможно Возможно
Read Committed Запрещено Возможно Возможно
Repeatable Read Запрещено Запрещено Возможно*
Serializable Запрещено Запрещено Запрещено

* В MySQL Repeatable Read также предотвращает фантомное чтение.

Снимок (snapshot) = моментальная копия всех данных базы на конкретный момент времени. Транзакция видит данные такими, какими они были в момент её начала (или момента последнего запроса — зависит от уровня изоляции).

Когда НЕ использовать Serializable

  1. Read-heavy reporting (>1000 TPS на чтение) — избыточные overhead
  2. Долгие batch-операции (>1 мин) — высокий риск serialization failures
  3. Высокая конкуренция записи (>50 concurrent writers на одни данные) — постоянные откаты

🟡 Middle Level

Детальное описание каждого уровня

Read Uncommitted

  • Транзакция видит незакоммиченные изменения других транзакций
  • Проблема: Если другая транзакция сделает ROLLBACK, вы получите данные, которых “никогда не существовало”
  • Использование: Крайне редко, для приблизительной статистики
  • PostgreSQL: Этот уровень отсутствует — автоматически заменяется на Read Committed. Это архитектурное решение, а не настройка — присутствует во всех версиях PG.

Read Committed

  • Самый популярный уровень по умолчанию (PostgreSQL, Oracle, SQL Server), потому что даёт достаточную защиту от грязного чтения при минимальных накладных расходах — нет блокировок чтения, нет serialization failures.
  • Внутри одной транзакции два одинаковых SELECT могут вернуть разные результаты
  • Реализуется через MVCC — снимок данных создаётся перед каждым запросом

Repeatable Read

  • Снимок данных создаётся один раз — при первом запросе в транзакции
  • MySQL (InnoDB): Уровень по умолчанию. Предотвращает фантомы через Next-Key Locking (Gap Locks)
  • PostgreSQL: При конфликте обновлений бросает ошибку сериализации

Serializable

  • Самый строгий и дорогой уровень
  • PostgreSQL: Использует SSI (Serializable Snapshot Isolation) — отслеживает зависимости между транзакциями
  • Приложение должно быть готово к retry при ошибке сериализации

Влияние на производительность

Чем выше уровень изоляции:

  • Тем больше блокировок или версий строк должна поддерживать БД
  • Тем выше вероятность конфликтов и откатов
  • На Serializable нужно реализовывать retry logic

Когда какой уровень использовать

  • Read Committed: 90% случаев, default для большинства приложений
  • Repeatable Read: Когда нужна стабильность данных внутри транзакции (отчёты)
  • Serializable: Финансовые операции, бронирование — где цена ошибки высока

🔴 Senior Level

Реализация в разных СУБД — ключевые различия

PostgreSQL Approach

  • По умолчанию: Read Committed
  • Использует MVCC с snapshot isolation
  • На Read Committed: новый снимок перед каждым оператором
  • На Repeatable Read: один снимок на всю транзакцию, при конфликте — ERROR: could not serialize access due to concurrent update
  • Serializable через SSI (Serializable Snapshot Isolation): граф зависимостей, detection cycles, selective abortion

MySQL (InnoDB) Approach

  • По умолчанию: Repeatable Read (исторически для statement-based replication)
  • Next-Key Locking = Record Lock + Gap Lock
  • Prevents phantoms на Repeatable Read (выходит за рамки ANSI SQL)
  • Higher deadlock probability из-за gap locks

MVCC Internal Mechanics

PostgreSQL:

  • Каждая tuple строки имеет xmin (transaction ID that inserted) и xmax (transaction ID that deleted/updated)
  • Visibility rules: транзакция видит строку, если xmin был committed до snapshot и xmax ещё не committed
  • Old versions хранятся в тех же страницах → bloat → VACUUM cleanup

MySQL/InnoDB:

  • Old versions хранятся в undo log в rollback segments
  • More efficient space usage, но сложнее recovery

Serializable Snapshot Isolation (PostgreSQL)

SSI отслеживает:

  • RW-dependencies: когда транзакция читает данные, которые другая транзакция потом меняет
  • Conflict detection: строится граф зависимостей, ищутся cycles
  • Transaction abort: при обнаружении dangerous structure одна транзакция abort-ится с SQLSTATE 40001

Application MUST implement retry logic:

@Retryable(value = {CannotSerializeTransactionException.class}, maxAttempts = 3)
@Transactional(isolation = Isolation.SERIALIZABLE)
public void criticalOperation() { ... }

Performance Benchmarks & Trade-offs

Уровень Throughput Latency Conflict Rate Use Case
Read Committed Highest Lowest ~0% General purpose
Repeatable Read Medium Medium Low-Medium Reports, batch processing
Serializable Lowest Highest High Financial, booking

Production Considerations

  • Connection pool exhaustion: Serializable может требовать больше retries → больше connections
  • Long-running transactions: На RR и Serializable держат старые версии строк дольше → bloat
  • Monitoring: Track serialization failure rate, tune accordingly
  • Alternative: Use pessimistic locking (SELECT FOR UPDATE) вместо Serializable для specific hot paths

🎯 Шпаргалка для интервью

Обязательно знать:

  • 4 уровня изоляции: Read Uncommitted, Read Committed, Repeatable Read, Serializable
  • Read Committed — дефолт в PostgreSQL, Oracle, SQL Server; Repeatable Read — дефолт в MySQL
  • Read Committed предотвращает только грязное чтение
  • Repeatable Read предотвращает dirty read + non-repeatable read
  • Serializable предотвращает все аномалии, но требует retry logic
  • PostgreSQL MVCC: новый snapshot перед каждым оператором на RC, один snapshot на RR
  • MySQL InnoDB использует Next-Key Locking (Record + Gap Lock) для предотвращения фантомов на RR
  • Serializable в PostgreSQL использует SSI с dependency graph и selective abort

Частые уточняющие вопросы:

  • Почему PostgreSQL не имеет Read Uncommitted? — Архитектурное решение: MVCC бесплатно предотвращает dirty reads
  • Чем Repeatable Read в MySQL отличается от PostgreSQL? — MySQL предотвращает фантомы через Gap Locks, PG — через MVCC snapshot
  • Когда использовать Serializable? — Финансовые операции, бронирование, где цена ошибки высока
  • Что такое serialization failure? — Ошибка 40001 при обнаружении RW-dependency cycle в SSI

Красные флаги (НЕ говорить):

  • “Repeatable Read во всех СУБД работает одинаково” — MySQL и PG фундаментально различаются
  • “Serializable = просто блокировки” — PostgreSQL использует SSI, не 2PL
  • “Read Committed = никаких аномалий” — возможны non-repeatable и phantom reads

Связанные темы:

  • [[1. Расшифруйте каждую букву ACID]]
  • [[3. Что такое Read Uncommitted]]
  • [[4. Что такое Read Committed]]
  • [[5. Что такое Repeatable Read]]
  • [[6. Что такое Serializable]]