Возможна ли аномалия «неповторяющееся чтение» (Non-Repeatable Read) на уровне изоляции Read Committed?

Ответ

Да, это классическая аномалия для уровня изоляции Read Committed.

  • Что гарантирует Read Committed: Этот уровень изоляции защищает только от "грязного чтения" (Dirty Read). То есть одна транзакция не может прочитать данные, которые были изменены другой транзакцией, но ещё не зафиксированы (COMMIT).

  • Что такое Non-Repeatable Read: Эта аномалия возникает, когда в рамках одной транзакции два последовательных чтения одной и той же строки возвращают разные результаты. Это происходит потому, что между этими чтениями другая транзакция успела изменить эти данные и зафиксировать свои изменения.

Пример в виде временной шкалы:

Представим, что на счете (id=1) изначально 100.

Время Транзакция 1 (Ваша) Транзакция 2 (Параллельная)
T1 BEGIN;
T2 SELECT balance FROM accounts WHERE id = 1;
-- Возвращает 100
T3 BEGIN;
T4 UPDATE accounts SET balance = 200 WHERE id = 1;
T5 COMMIT;
T6 SELECT balance FROM accounts WHERE id = 1;
-- Возвращает 200!
T7 COMMIT;

В момент T6 Транзакция 1 получает другой результат для того же запроса, что и в T2. Это и есть "неповторяющееся чтение".

Для предотвращения этой аномалии необходимо использовать более строгий уровень изоляции, например, Repeatable Read.

Ответ 18+ 🔞

А, ну это же классика, блядь, ёпта! Просто учебник по аномалиям, в рот меня чих-пых!

Смотри, смотри, что тут происходит. Уровень Read Committed — он как такой хитрожопый сторож: он не пустит тебя читать чужие недоделанные, грязные данные. То есть, пока кто-то там обновляет запись и не нажал COMMIT, ты её в говняном виде не увидишь. Вроде норм, да?

А хуй там! Он тебя не защищает от другой, ещё более ебенейшей хуйни — от Non-Repeatable Read! Это когда ты, сука, в своей транзакции два раза подряд читаешь одну и ту же строку, а она тебе, блядь, разные цифры показывает! Как так-то, а? Волнение ебать!

Сейчас на пальцах, на примере этого сраного счёта с id=1. Изначально там 100 рублей, допустим.

Время Твоя транзакция (Т1) Какая-то левая параллельная транзакция (Т2)
T1 BEGIN; (Начинаем!)
T2 SELECT balance FROM accounts WHERE id = 1;
→ Видишь 100. Всё чётко.
T3 BEGIN; (А тут кто-то другой тоже начал!)
T4 UPDATE accounts SET balance = 200 WHERE id = 1; (Он взял и обновил твой счёт!)
T5 COMMIT; (И зафиксировал! Всё, данные сменились!)
T6 SELECT balance FROM accounts WHERE id = 1;
→ А тут тебе уже 200 вываливается!
T7 COMMIT;

Видишь, в чём пиздец? В момент T6 ты делаешь ТОТ ЖЕ САМЫЙ запрос, что и в T2, а он тебе уже другую хуйню показывает! Это и есть «неповторяющееся чтение». Ты не можешь повторить свой же запрос и получить тот же результат! Удивление пиздец!

И Read Committed на это плевать с высокой колокольни. Он свою работу сделал — грязь не показал. А то, что данные под тобой сменились — это уже твои личные проблемы, чувак.

Что делать? Да повышать уровень изоляции, блядь! Надо ставить Repeatable Read. Вот этот уровень уже встанет горой и скажет: «Нет, сука, раз ты в начале транзакции увидел 100, то до самого её конца ты будешь видеть 100, даже если весь мир вокруг уже обновился!». Вот так вот.

Короче, запомни: Read Committed — защита только от говна. От всей остальной ебли — нет.