Какая проблема возникает при уровне изоляции Repeatable Read, которую он не решает
Что проверяют
Знаете ли вы, что ответ зависит от базы, а не только от таблицы из стандарта SQL. Хрестоматийный ответ «фантомное чтение» засчитают, но следом почти всегда спрашивают: есть ли фантомы на этом уровне в PostgreSQL и MySQL и как вы защищаетесь от оставшейся аномалии в Spring-приложении.
Как отвечать
Начните со стандарта: Repeatable Read гарантирует, что прочитанные строки не изменятся до конца транзакции, но допускает фантомы. Повторный SELECT ... WHERE status = 'NEW' может вернуть строки, которые вставила и закоммитила соседняя транзакция.
Потом покажите, как это устроено в реальных базах:
- PostgreSQL: Repeatable Read работает как снимок данных, фантомов при чтении нет. Не решена другая аномалия, write skew: две транзакции читают одно и то же, каждая проверяет условие и меняет разные строки. Классика: два дежурных врача видят, что на смене двое, и каждый снимает себя. Обе транзакции коммитятся, на смене никого;
- MySQL InnoDB: здесь Repeatable Read включён по умолчанию. Обычный
SELECTчитает снимок, аSELECT ... FOR UPDATEставит next-key locks и закрывает фантомы в диапазоне. Зато возможно потерянное обновление:UPDATEвидит последнюю закоммиченную версию строки, а не снимок; - Serializable: убирает и фантомы, и write skew, но в PostgreSQL платой становятся ошибки сериализации (
SQLSTATE 40001), и транзакцию нужно повторять.
В Java уровень задают через @Transactional(isolation = Isolation.REPEATABLE_READ) или Connection.TRANSACTION_REPEATABLE_READ. От write skew защищают блокировкой строк (SELECT ... FOR UPDATE, в Spring Data JPA это @Lock(LockModeType.PESSIMISTIC_WRITE)) или уровнем Serializable с ретраем.
Где спотыкаются
Отвечают только по таблице стандарта и уверенно говорят, что в PostgreSQL на Repeatable Read бывают фантомы.
Путают фантомное чтение с неповторяющимся: неповторяющееся касается изменения уже прочитанной строки, фантом касается появления новых строк под тем же условием.
Предлагают Serializable как бесплатное решение и не упоминают, что приложение обязано ловить ошибку сериализации и повторять транзакцию. Без ретрая пользователь просто получит ошибку 500.