Ответ
Фантомное чтение — это аномалия параллельного доступа, при которой одна транзакция при повторном выполнении одного и того же запроса видит новые строки («фантомы»), которые были добавлены другой, уже завершённой транзакцией в промежутке между этими чтениями.
Отличие от других аномалий:
- Неповторяющееся чтение (Non-repeatable read): Изменяются данные в существующих строках.
- Фантомное чтение: Появляются совершенно новые строки, удовлетворяющие условию запроса.
Пример сценария:
-- Уровень изоляции: READ COMMITTED (или ниже)
-- Транзакция A | -- Транзакция B
BEGIN TRANSACTION; |
SELECT * FROM users WHERE age > 25; |
-- Результат: 3 строки |
| BEGIN TRANSACTION;
| INSERT INTO users (name, age) VALUES ('Carl', 30);
| COMMIT; -- Добавлена новая строка с age=30
SELECT * FROM users WHERE age > 25; |
-- Результат: 4 строки! Появился "фантом" |
COMMIT; |
Как предотвратить:
- Уровень изоляции
SERIALIZABLE– Гарантированно предотвращает фантомные чтения, блокируя диапазоны строк. - Использование диапазонных блокировок – Например,
SELECT ... FOR UPDATEс условием, которое блокирует вставку в защищаемый диапазон (зависит от СУБД).
В Spring (Java):
@Transactional(isolation = Isolation.SERIALIZABLE)
public void someCriticalMethod() {
// ... логика, чувствительная к фантомному чтению
}
Почему это проблема: Фантомные чтения могут нарушить бизнес-логику, основанную на агрегации или проверке существования данных (например, подсчёт суммы по условию или проверка уникальности).