Раздел 10 · Databases

Проблемы параллелизма и уровни изоляции

junior~15 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке мы назвали изоляцию самой хитрой буквой ACID. Если бы транзакции шли строго по очереди, проблем бы не было. Но база обслуживает сотни пользователей одновременно, и их транзакции перемешиваются. Этот урок про то, что ломается при таком перемешивании, и про уровни изоляции: ручку, которой ты выбираешь, от каких поломок защищаться.

Общий документ

Представь документ, который одновременно правят два человека. Пока ты пишешь абзац, коллега читает его недописанным. Ты перечитываешь таблицу, а в ней уже другие числа. Вы оба исправили одну цифру, и победила правка того, кто сохранил последним. Каждая из этих сцен в базах данных имеет своё имя.

Четыре аномалии

Проблемы одновременной работы называют аномалиями параллелизма. Разберём четыре главные на балансе Пети, где лежит 10000 рублей.

Грязное чтение

T1: UPDATE balance = 5000   (оплата, ещё не зафиксирована)
T2: SELECT balance  → 5000  (видит незафиксированное)
T1: ROLLBACK                (оплата отменилась)

T2 прочитала 5000, которых в базе так и не случилось. Чтение незафиксированных изменений называют грязным чтением.

Неповторяемое чтение

T2: SELECT balance  → 10000
T1: UPDATE balance = 5000; COMMIT
T2: SELECT balance  → 5000  (тот же запрос, другой ответ)

Здесь T2 видит только зафиксированное, но одно и то же чтение внутри её транзакции дало два разных ответа. Это неповторяемое чтение. Отчёт, который сначала считает сумму, а потом детали, разойдётся сам с собой.

Фантомное чтение

T2: SELECT count(*) FROM enrollments WHERE course_id = 10  → 30
T1: INSERT INTO enrollments ... (course_id = 10); COMMIT
T2: SELECT count(*) FROM enrollments WHERE course_id = 10  → 31

Старые строки не менялись, но появилась новая, подходящая под условие. Её называют фантомом.

Потерянное обновление

Приложение списывает деньги так: прочитало баланс, посчитало новый, записало.

T1: SELECT balance → 10000
T2: SELECT balance → 10000
T1: UPDATE balance = 10000 - 5000; COMMIT   → 5000
T2: UPDATE balance = 10000 - 3000; COMMIT   → 7000

Петя купил два курса, а списалось только 3000. Первая запись затёрта второй. Это потерянное обновление, ровно та беда с двумя тренерами из самого первого урока.

дальше после входа

Урок целиком открыт всем, кто вошёл. Войди по своему email, чтобы читать дальше.

Вход пока по приглашению. Если хочешь учиться, напиши Vassiliy.