Какие побочные эффекты возникают при изменении уровня изоляции транзакций в БД?

«Какие побочные эффекты возникают при изменении уровня изоляции транзакций в БД?» — вопрос из категории Базы данных, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Уровень изоляции транзакции определяет, насколько изменения, сделанные в одной транзакции, видны другим параллельным транзакциям, и как они защищены от взаимного влияния. Повышение уровня изоляции усиливает целостность данных, но снижает производительность и параллелизм из-за блокировок.

Побочные эффекты (аномалии), которые могут проявиться при НИЗКИХ уровнях изоляции:

  1. Dirty Read (Грязное чтение):

    • Что это: Транзакция читает незафиксированные изменения другой транзакции. Если та транзакция откатится, первая прочитает «мусорные» данные.
    • Когда возникает: Уровень READ UNCOMMITTED.
    • Пример: Транзакция A видит новые цены, которые транзакция B еще не подтвердила. B откатывается, но A уже работала с несуществующими данными.
  2. Non-Repeatable Read (Неповторяющееся чтение):

    • Что это: В рамках одной транзакции два одинаковых запроса возвращают разные данные для одних и тех же строк, потому что другая транзакция изменила и зафиксировала эти строки между запросами.
    • Когда возникает: Уровень READ COMMITTED (стандартный для многих СУБД).
    • Пример: Транзакция A дважды читает баланс счета. Между чтениями транзакция B снимает деньги и коммитится. Второе чтение в A покажет новый, уменьшенный баланс.
  3. Phantom Read (Фантомное чтение):

    • Что это: Похоже на неповторяющееся чтение, но касается появления или исчезновения строк (наборов данных), а не изменения существующих. Два одинаковых запроса возвращают разное количество строк.
    • Когда возникает: Уровень REPEATABLE READ.
    • Пример: Транзакция A выбирает все заказы за сегодня. Транзакция B создает новый заказ и коммитится. Если A повторит запрос, она увидит «фантомную» новую строку.

Побочные эффекты при ВЫСОКИХ уровнях изоляции:

  1. Increased Locking & Contention (Рост блокировок и конфликтов):
    • Что это: Уровень SERIALIZABLE для предотвращения всех аномалий использует строгие блокировки (например, блокировки диапазонов ключей). Это приводит к:
      • Увеличению времени ожидания (deadlocks).
      • Снижению пропускной способности (throughput).
      • Риску взаимоблокировок (deadlock), которые СУБД вынуждена разрешать, откатывая одну из транзакций.

Практический пример выбора уровня в коде (C# ADO.NET):

using (var connection = new SqlConnection(connectionString))
{
    await connection.OpenAsync();
    // Выбор уровня изоляции — компромисс между целостностью и производительностью
    using (var transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        try
        {
            var command = connection.CreateCommand();
            command.Transaction = transaction;
            command.CommandText = "UPDATE Accounts SET Balance = Balance - 100 WHERE Id = 1";
            await command.ExecuteNonQueryAsync();

            // На уровне ReadCommitted здесь невозможно грязное чтение,
            // но возможно неповторяющееся чтение.
            transaction.Commit(); // Фиксация изменений
        }
        catch
        {
            transaction.Rollback(); // Откат в случае ошибки
            throw;
        }
    }
}

Вывод: Выбор уровня изоляции — это баланс между консистентностью данных (требованиями бизнес-логики) и производительностью приложения. Чаще всего используется Read Committed как разумный компромисс.