Какие проблемы могут возникать при параллельном доступе с использованием транзакций?
При параллельном выполнении транзакций возникают аномалии чтения и записи, которые могут привести к некорректным результатам. Стандарт SQL определяет четыре основных типа аномалий.
Потерянное обновление (Lost Update)
Две транзакции одновременно читают одно значение и записывают свои изменения. Последняя запись перезатирает первую.
Пример
T1: READ balance = 100
T2: READ balance = 100
T1: WRITE balance = 100 + 50 = 150
T2: WRITE balance = 100 - 30 = 70 ← изменение T1 потеряно
Результат: баланс = 70 вместо ожидаемых 120. Предотвращается на всех уровнях изоляции (через блокировки или MVCC).
Грязное чтение (Dirty Read)
Транзакция читает данные, изменённые другой транзакцией, которая ещё не зафиксирована и может быть откачена.
Пример
T1: UPDATE balance = 50 (не зафиксировано)
T2: READ balance = 50 ← грязное чтение
T1: ROLLBACK ← balance вернулся к 100
T2: использует значение 50 ← некорректное
Предотвращается на уровне Read Committed и выше.
Неповторяемое чтение (Non-Repeatable Read)
Транзакция дважды читает одну строку и получает разные значения, потому что между чтениями другая транзакция изменила и зафиксировала данные.
Пример
T1: READ balance = 100
T2: UPDATE balance = 200
T2: COMMIT
T1: READ balance = 200 ← значение изменилось
Предотвращается на уровне Repeatable Read и выше.
Фантомное чтение (Phantom Read)
Транзакция дважды выполняет запрос с одним условием и получает разное количество строк, потому что между запросами другая транзакция добавила или удалила строки.
Пример
T1: SELECT COUNT(*) FROM orders WHERE status = 'new' → 5
T2: INSERT INTO orders (status) VALUES ('new')
T2: COMMIT
T1: SELECT COUNT(*) FROM orders WHERE status = 'new' → 6 ← фантом
Отличие от неповторяемого чтения: неповторяемое чтение — изменение существующих строк, фантом — появление или исчезновение строк.
Предотвращается на уровне Serializable (или Repeatable Read в PostgreSQL).
Сводная таблица
| Аномалия | Суть | Минимальный уровень защиты |
|---|---|---|
| Потерянное обновление | Перезатирание чужих изменений | Read Uncommitted |
| Грязное чтение | Чтение незафиксированных данных | Read Committed |
| Неповторяемое чтение | Изменение ранее прочитанных строк | Repeatable Read |
| Фантомное чтение | Появление/исчезновение строк | Serializable |
Пример фантомного чтения (SQL)
| Транзакция 1 | Транзакция 2 |
|---|---|
SELECT SUM(f2) FROM tbl1; |
|
INSERT INTO tbl1 (f1,f2) VALUES (15,20); |
|
COMMIT; |
|
SELECT SUM(f2) FROM tbl1; – другой результат |
Второй SELECT в Транзакции 2 возвращает другую сумму, потому что появилась новая строка (фантом).
На собеседовании: интервьюер хочет, чтобы кандидат объяснил каждую аномалию с примером и знал, какой уровень изоляции от какой аномалии защищает. Частая ошибка — путать неповторяемое чтение (изменение строки) и фантомное чтение (появление/исчезновение строк).