Ответ
Да, это классическая аномалия для уровня изоляции 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 — защита только от говна. От всей остальной ебли — нет.