Уровни изоляции транзакций: READ UNCOMMITTED, READ COMMITTED и др.

Что такое уровни изоляции транзакций? 🔄

Когда несколько транзакций выполняются одновременно, база данных должна обеспечить их корректное взаимодействие. Уровни изоляции определяют, какие "побочные эффекты" одной транзакции могут быть видны другой.

Представьте, что транзакции — это люди в офисе: одни читают документы, другие их меняют. Уровень изоляции — это правила, определяющие, когда изменения становятся видны коллегам.

Проблемы параллельного выполнения

Прежде чем разбирать уровни, познакомимся с тремя ключевыми проблемами:

  1. "Грязное" чтение (Dirty Read) 📖
    Чтение незафиксированных данных из другой транзакции. Если та транзакция откатится, вы прочитаете мусор.

  2. Неповторяемое чтение (Non-repeatable Read) 🔄
    Повторное чтение тех же данных в рамках одной транзакции возвращает разные результаты, потому что другая транзакция изменила их.

  3. Фантомное чтение (Phantom Read) 👻
    Появление новых строк при повторном выполнении того же запроса, потому что другая транзакция добавила подходящие данные.


Четыре уровня изоляции ANSI SQL

Стандарт SQL определяет четыре уровня (от самого слабого к самому строгому):

1. READ UNCOMMITTED — чтение незафиксированных данных

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
  • Разрешает все три проблемы (грязное, неповторяемое и фантомное чтение)
  • Самый быстрый, но самый опасный уровень
  • Используется редко, только для агрегаций, где точность не критична

Пример:
Транзакция 1 изменяет баланс, но не фиксирует. Транзакция 2 уже видит это изменение. Если Транзакция 1 откатится, Транзакция 2 работала с несуществующими данными.


2. READ COMMITTED — чтение подтверждённых данных

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • Запрещает грязное чтение ✅
  • Разрешает неповторяемое и фантомное чтение ❌
  • Дефолтный уровень в PostgreSQL и Oracle

Как работает:
База данных запоминает состояние данных на момент начала каждого оператора SELECT.

Пример:

-- Транзакция 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;

-- Транзакция 2 (READ COMMITTED)
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- Не увидит изменения
COMMIT;

-- После COMMIT в Транзакции 1
SELECT balance FROM accounts WHERE id = 1; -- Увидит новое значение

3. REPEATABLE READ — повторяемое чтение

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
  • Запрещает грязное и неповторяемое чтение ✅
  • Разрешает фантомы ❌
  • Дефолтный уровень в MySQL (InnoDB)

Как работает:
База запоминает состояние данных на момент начала транзакции для всех SELECT.

Пример в MySQL:

-- Транзакция 1
BEGIN;
SELECT * FROM accounts WHERE id = 1; -- Читает начальное значение

-- Транзакция 2 изменяет и фиксирует данные
UPDATE accounts SET balance = 500 WHERE id = 1;
COMMIT;

-- Транзакция 1 снова читает
SELECT * FROM accounts WHERE id = 1; -- Увидит старое значение!

4. SERIALIZABLE — полная изоляция

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
  • Запрещает все три проблемы ✅
  • Эмулирует последовательное выполнение транзакций
  • Самый медленный, но самый безопасный уровень

Как работает:
База блокирует данные, создавая эффект выполнения транзакций строго по очереди.


Какой уровень выбрать? 🤔

Уровень Грязное чтение Неповторяемое Фантомы Производительность
READ UNCOMMITTED Да Да Да ⚡⚡⚡⚡⚡
READ COMMITTED Нет Да Да ⚡⚡⚡⚡
REPEATABLE READ Нет Нет Да ⚡⚡⚡
SERIALIZABLE Нет Нет Нет

Эмпирическое правило:
Используйте самый слабый уровень, который допустим для вашей бизнес-логики. Для финансовых операций — SERIALIZABLE, для аналитических отчётов — READ COMMITTED.


Практический пример: банковский перевод 💸

-- Настройка строгой изоляции для финансовой операции
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN;

-- Проверка баланса
SELECT balance FROM accounts WHERE user_id = 1 FOR UPDATE;

-- Если баланс достаточен...
UPDATE accounts SET balance = balance - 100 WHERE user_id = 1;
UPDATE accounts SET balance = balance + 100 WHERE user_id = 2;

COMMIT;

Обратите внимание на FOR UPDATE — это блокировка строк для предотвращения изменений из других транзакций.


Под капотом: как СУБД реализуют изоляцию

  1. Блокировки 🔒
    Пессимистичный подход: данные блокируются на время транзакции.

  2. Версионность (MVCC) 📑
    Оптимистичный подход (используется в PostgreSQL): каждое изменение создаёт новую версию строки, старая остаётся для других транзакций.

  3. Снимки данных (Snapshot Isolation) 📸
    Транзакция работает с "фотографией" данных на момент своего начала.

Скрыть рекламу навсегда

📘 VK Видео — обучение без ограничений

Все уроки доступны без VPN, без блокировок и зависаний.

Можно смотреть с телефона, планшета или компьютера — в любое время.

▶️ Смотреть на VK Видео