> Какой уровень изоляции транзакций по умолчанию в PostgreSQL (C# /.NET, Go, PostgreSQL)

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

Компании: Wildberries, InDrive, Ozon, Сбер, Kalabi

Стек: C# /.NET, Go, PostgreSQL

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

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

В PostgreSQL уровень изоляции транзакций по умолчанию - Read Committed. Это означает, что каждая команда внутри транзакции видит только те данные, которые были зафиксированы до начала выполнения этой команды. Этот уровень предотвращает dirty reads, но допускает non-repeatable reads и phantom reads. Настройка задаётся параметром default_transaction_isolation и может быть изменена для конкретной транзакции или сессии.

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

PostgreSQL поддерживает четыре уровня изоляции, определённые стандартом SQL, но реализует их через механизм многоверсионности (MVCC). Уровень по умолчанию - Read Committed, и это осознанный выбор разработчиков СУБД.

В отличие от многих других СУБД, где Read Committed реализован через блокировки, PostgreSQL использует snapshot-based подход. Для каждой команды внутри транзакции создаётся новый snapshot - срез данных на момент начала выполнения этой команды. Это ключевое отличие от Repeatable Read, где snapshot создаётся один раз на всю транзакцию.

Важно понимать поведение на уровне команд:

  • Каждый SELECT, UPDATE, DELETE или INSERT ... ON CONFLICT получает свежий snapshot.
  • Если команда изменяет строки, которые были изменены и зафиксированы другой транзакцией после создания snapshot, PostgreSQL автоматически перезапускает команду (EvalPlanQual recheck) с новым snapshot, чтобы применить изменения к актуальной версии строк.
  • Это может привести к тому, что UPDATE затронет строки, которые не были видны в момент начала команды, если они были изменены параллельной транзакцией.

Для сравнения, в Repeatable Read snapshot фиксируется на момент первого запроса в транзакции, и все последующие команды видят одни и те же данные. Это даёт более строгие гарантии, но увеличивает вероятность конфликтов сериализации при конкурентной записи.

На практике

Для backend-разработчика на C# или Go важно учитывать следующее:

  • При работе с высоконагруженными системами, где требуется консистентность данных на уровне транзакции, часто переключаются на Repeatable Read или Serializable.
  • Read Committed подходит для большинства OLTP-сценариев, где важна производительность и конкурентность, а не строгая повторяемость чтений.
  • Если вы используете ORM (например, Entity Framework Core или GORM), убедитесь, что вы явно задаёте уровень изоляции, если требуется отличный от дефолтного.
  • При использовании пула соединений (Npgsql, pgx) помните, что настройки сессии могут "протекать" между транзакциями, если не сбрасывать их явно.

Пример настройки уровня изоляции:

SQL
-- для текущей транзакции
BEGIN ISOLATION LEVEL REPEATABLE READ;
-- для текущей сессии
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;
-- глобально (требует прав суперпользователя)
ALTER SYSTEM SET default_transaction_isolation = 'repeatable read';

Пример кода

На Go с драйвером pgx:

GO
tx, err := db.BeginTx(ctx, &sql.TxOptions{
Isolation: sql.LevelRepeatableRead,
})
if err != nil {
log.Fatal(err)
}
defer tx.Rollback()
// выполнение запросов в транзакции
_, err = tx.ExecContext(ctx, "UPDATE accounts SET balance = balance - 100 WHERE id = $1", 1)
if err != nil {
log.Fatal(err)
}
err = tx.Commit()

На C# с Npgsql:

CSHARP
await using var connection = new NpgsqlConnection(connectionString);
await connection.OpenAsync();
await using var transaction = await connection.BeginTransactionAsync(IsolationLevel.RepeatableRead);
await using var command = connection.CreateCommand();
command.Transaction = transaction;
command.CommandText = "UPDATE accounts SET balance = balance - 100 WHERE id = @id";
command.Parameters.AddWithValue("id", 1);
await command.ExecuteNonQueryAsync();
await transaction.CommitAsync();

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

Начните с прямого ответа: "Read Committed". Затем кратко объясните, что это значит на практике: каждая команда видит только зафиксированные данные на момент своего начала. Упомяните, что PostgreSQL реализует это через MVCC и создаёт snapshot для каждой команды, а не для всей транзакции.

Если интервьюер углубляется, расскажите про отличия от Repeatable Read и Serializable. Подчеркните, что в Read Committed возможны non-repeatable reads и phantom reads, но нет dirty reads. Приведите пример, когда это может быть проблемой: например, при чтении суммы на счёте дважды в одной транзакции.

Хорошо показать понимание механизма EvalPlanQual - автоматического перезапуска команд при конфликте с параллельными изменениями. Это отличает PostgreSQL от многих других СУБД.

Завершите практическим советом: для большинства сценариев Read Committed достаточно, но для финансовых операций или отчётов лучше использовать Repeatable Read или Serializable.

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

Интервьюер оценивает:

  • Базовое знание стандарта SQL и уровней изоляции.
  • Понимание, как именно PostgreSQL реализует Read Committed, а не просто заученное определение.
  • Умение объяснить trade-off между консистентностью и производительностью.
  • Практический опыт: знает ли кандидат, как менять уровень изоляции, и какие подводные камни есть при работе с пулом соединений.
  • Способность связать теорию с реальными сценариями разработки backend-приложений.

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

  • Утверждение, что в PostgreSQL по умолчанию Repeatable Read - это распространённое заблуждение, особенно у тех, кто работал с Oracle или MySQL.
  • Смешивание понятий snapshot для команды и snapshot для транзакции.
  • Утверждение, что Read Committed полностью исключает аномалии - на самом деле он допускает non-repeatable reads и phantom reads.
  • Игнорирование механизма EvalPlanQual при объяснении поведения UPDATE в конкурентной среде.
  • Непонимание, что уровень изоляции - это настройка сессии, а не глобальная для всей СУБД, и её можно менять для конкретной транзакции.

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

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