Что такое «фантомное чтение» и «неповторяющееся чтение» в контексте транзакций?

«Что такое «фантомное чтение» и «неповторяющееся чтение» в контексте транзакций?» — вопрос из категории Базы данных, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Это две аномалии согласованности, которые могут возникать при параллельном выполнении транзакций, в зависимости от уровня изоляции.

Неповторяющееся чтение (Non-repeatable Read)

  • Суть: В рамках одной транзакции два одинаковых запроса SELECT возвращают разные данные для одних и тех же строк из-за того, что другая параллельная транзакция изменила и зафиксировала эти данные между первым и вторым чтением.
  • Пример:
    1. Транзакция A читает баланс счета (100$).
    2. Транзакция B изменяет баланс этого счета на 50$ и фиксирует изменения.
    3. Транзакция A снова читает баланс того же счета и получает 50$ (результат изменился).

Фантомное чтение (Phantom Read)

  • Суть: В рамках одной транзакции два одинаковых запроса SELECT возвращают разное количество строк из-за того, что другая параллельная транзакция добавила или удалила строки, удовлетворяющие условию запроса, между первым и вторым чтением.
  • Пример:
    1. Транзакция A выполняет SELECT * FROM users WHERE age > 18 и получает 10 строк.
    2. Транзакция B вставляет новую запись с age=25 и фиксирует изменения.
    3. Транзакция A повторяет тот же SELECT и получает 11 строк (появилась "фантомная" строка).

Как предотвращаются?

  • Неповторяющееся чтение предотвращается на уровнях изоляции REPEATABLE READ и выше.
  • Фантомное чтение в стандарте SQL предотвращается только на уровне SERIALIZABLE. Однако некоторые СУБД (например, MySQL InnoDB при REPEATABLE READ) также предотвращают фантомы за счёт механизма многоверсионности (MVCC) и gap-блокировок.