> Какие уровни изоляции транзакций существуют и как они помогают избежать проблем с конкурентным доступом? (PHP)

Уровень: senior · Роль: backend · Язык: PHP · Категория: Технические вопросы

Компании: vanta

Стек: PHP, PostgreSQL

> Пример ответа

Короткий ответ

В PostgreSQL существует четыре уровня изоляции транзакций: read uncommitted, read committed, repeatable read и serializable. Они определяют, какие аномалии конкурентного доступа допустимы: dirty read, non-repeatable read, phantom read и serialization anomaly. Уровни отличаются trade-off между консистентностью данных и производительностью. В PostgreSQL read uncommitted фактически работает как read committed, а serializable использует SSI (serializable snapshot isolation) для полной защиты от аномалий.

Подробное объяснение

Стандарт SQL определяет четыре уровня изоляции, каждый из которых предотвращает определённый набор аномалий:

  1. Read uncommitted - транзакция видит незакоммиченные изменения других транзакций (dirty read). В PostgreSQL этот уровень не реализован как отдельный: он работает как read committed, потому что dirty read запрещены на уровне MVCC.

  2. Read committed - каждая команда в транзакции видит snapshot данных на момент начала команды. Предотвращает dirty read, но допускает non-repeatable read: повторный SELECT в одной транзакции может вернуть разные данные, если другая транзакция закоммитила изменения между командами.

  3. Repeatable read - транзакция видит snapshot на момент первого запроса. Предотвращает non-repeatable read и phantom read (в PostgreSQL - полностью, в отличие от стандарта, где phantoms допускаются). Конфликтующие изменения приводят к ошибке serialization failure.

  4. Serializable - самый строгий уровень. Гарантирует, что результат конкурентного выполнения транзакций эквивалентен некоторому последовательному порядку. Использует SSI (serializable snapshot isolation), который отслеживает зависимости между транзакциями и прерывает одну из конфликтующих.

Аномалии, которые предотвращаются на каждом уровне:

УровеньDirty readNon-repeatable readPhantom readSerialization anomaly
Read uncommittedвозможновозможновозможновозможно
Read committedнетвозможновозможновозможно
Repeatable readнетнетнет (в PG)возможно
Serializableнетнетнетнет

В PostgreSQL механизм MVCC (multiversion concurrency control) лежит в основе всех уровней: каждая транзакция работает со своим snapshot версий строк, что исключает блокировки чтения.

На практике

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

  • Read committed - дефолт в PostgreSQL. Подходит для большинства OLTP-нагрузок: короткие транзакции, где допустима небольшая нестабильность чтения между командами.
  • Repeatable read - нужен, когда в рамках одной транзакции выполняется несколько SELECT, и результаты должны быть согласованы между собой. Например, формирование отчёта или расчёт баланса.
  • Serializable - для критичных бизнес-операций, где важна полная предсказуемость: финансовые операции, бронирование, инвентаризация. Требует обработки serialization failures и retry-логики.

При использовании repeatable read и serializable важно помнить: если две транзакции изменяют одну и ту же строку, вторая получит ошибку 40001 serialization_failure при попытке commit. Это не баг, а механизм защиты - приложение должно обрабатывать эту ошибку и повторять транзакцию.

Также стоит учитывать, что более высокий уровень изоляции увеличивает накладные расходы на отслеживание зависимостей (особенно SSI) и может снизить пропускную способность при высокой конкуренции.

Пример кода

PHP
// Установка уровня изоляции в PHP с PDO и PostgreSQL
$pdo = new PDO('pgsql:host=localhost;dbname=test', 'user', 'pass');
// Read committed (по умолчанию)
$pdo->exec('BEGIN ISOLATION LEVEL READ COMMITTED');
// Repeatable read
$pdo->exec('BEGIN ISOLATION LEVEL REPEATABLE READ');
// Serializable
$pdo->exec('BEGIN ISOLATION LEVEL SERIALIZABLE');
// Пример обработки serialization failure
try {
$pdo->beginTransaction();
$pdo->exec('SET TRANSACTION ISOLATION LEVEL SERIALIZABLE');
// Бизнес-логика: чтение и запись
$stmt = $pdo->query('SELECT balance FROM accounts WHERE id = 1');
$balance = $stmt->fetchColumn();
$pdo->exec('UPDATE accounts SET balance = ' . ($balance - 100) . ' WHERE id = 1');
$pdo->commit();
} catch (PDOException $e) {
if ($e->getCode() === '40001') { // serialization_failure
// retry логика
$pdo->rollBack();
// повторная попытка с ограничением по количеству
} else {
throw $e;
}
}

Как отвечать на собеседовании

Начни с перечисления уровней и их ключевых отличий. Затем объясни, какие аномалии каждый уровень предотвращает, и обязательно упомяни особенности PostgreSQL: read uncommitted не отличается от read committed, а repeatable read полностью исключает phantom read. Покажи понимание MVCC как основы механизма. Приведи практический пример выбора уровня для конкретной задачи. Если спросят про serializable - расскажи про SSI и обработку serialization failure. Хорошо, если упомянешь trade-off между консистентностью и производительностью.

Что проверяет интервьюер

  • Понимание стандарта SQL и его реализации в конкретной СУБД
  • Знание аномалий конкурентного доступа и их определений
  • Умение выбирать уровень изоляции под задачу
  • Понимание внутренних механизмов: MVCC, snapshot, SSI
  • Практический опыт: обработка ошибок сериализации, настройка транзакций
  • Способность объяснить trade-off и последствия выбора

Типичные ошибки

  • Путаница между read committed и repeatable read: непонимание, что в read committed snapshot создаётся на каждую команду, а в repeatable read - на всю транзакцию
  • Утверждение, что read uncommitted в PostgreSQL позволяет dirty read - это не так
  • Игнорирование того, что phantom read в PostgreSQL на уровне repeatable read полностью исключён, в отличие от стандарта
  • Отсутствие упоминания serialization failure и необходимости retry-логики
  • Смешение уровней изоляции с блокировками: важно подчеркнуть, что в PostgreSQL используется MVCC, а не блокировки чтения
  • Выбор serializable без понимания его стоимости и альтернатив (например, явные блокировки или оптимистичная конкуренция)

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью