Какие существуют аномалии параллельных транзакций в базах данных?

Ответ

При одновременном доступе нескольких транзакций к одним и тем же данным могут возникать следующие аномалии:

  1. Потерянное обновление (Lost Update) Происходит, когда две транзакции читают одну и ту же запись, обе изменяют её, а затем сохраняют. Изменение, сделанное первой транзакцией, будет перезаписано второй. Пример: Два пользователя одновременно редактируют статью. Первый сохраняет изменения, а через секунду второй сохраняет свои, затирая работу первого.

  2. «Грязное» чтение (Dirty Read) Одна транзакция читает данные, которые были изменены другой транзакцией, но ещё не зафиксированы (не выполнен COMMIT). Если вторая транзакция в итоге будет отменена (ROLLBACK), первая будет работать с неактуальными, "грязными" данными.

  3. Неповторяемое чтение (Non-Repeatable Read) В рамках одной транзакции происходит повторное чтение одной и той же строки, но результаты оказываются разными. Это случается, если между чтениями другая транзакция успела изменить или удалить эту строку и зафиксировать изменения.

  4. Фантомное чтение (Phantom Read) Похоже на неповторяемое чтение, но связано с появлением новых записей. Когда одна транзакция повторно выполняет запрос с одним и тем же условием WHERE, она получает разное количество строк, потому что другая транзакция успела добавить новые строки, удовлетворяющие этому условию.

Способы борьбы:

  • Уровни изоляции транзакций: Основной механизм в SQL. Уровни (READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE) определяют, какие аномалии допустимы, а какие нет, обеспечивая компромисс между согласованностью данных и производительностью.
  • Блокировки:
    • Пессимистические: Явная блокировка записей на время их чтения и изменения (например, SELECT ... FOR UPDATE в PostgreSQL), чтобы другие транзакции не могли их изменять.
    • Оптимистические: Проверка перед записью, не изменились ли данные с момента их чтения (например, с помощью поля version). Если изменились — транзакция откатывается.

Ответ 18+ 🔞

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

  1. Потерянное обновление (Lost Update) Вообще пиздец, классика. Два чела одновременно хватают один файл, оба его меняют и сохраняют. Кто последний нажал «Сохранить», тот и красавчик, а работа первого — накрылась медным тазом, в топку. Пример: Сидят два редактора в одной статье. Вася дописал гениальный абзац, сохранил. А Петя, который на секунду позже начал, тупо затер всё Васино своим кривым текстом и тоже сохранил. Вася в ауте.

  2. «Грязное» чтение (Dirty Read) Тут один чувак уже начал менять данные, но ещё не сказал «ВСЁ, ГОТОВО!» (то есть COMMIT не сделал). А второй, нетерпеливый, уже суёт свой нос и читает эти сырые, промежуточные данные. А если первый потом передумает и откатит всё нахуй (ROLLBACK), то второй останется с полной хуйней в руках, с которой уже поработал. Э сабака, сука!

  3. Неповторяемое чтение (Non-Repeatable Read) Ситуация для параноиков. Ты в рамках своей операции прочитал какую-то строчку. Отвлёкся на секунду, а когда через мгновение перечитал её — а там уже другие цифры! Оказалось, пока ты моргал, другая транзакция проскочила и эти данные поменяла. Волнение ебать, где правда?

  4. Фантомное чтение (Phantom Read) Это ещё хитрее, блядь. Ты два раза подряд делаешь один и тот же запрос, например «дай всех, у кого зарплата больше ста». В первый раз тебе вернулось 10 записей. Ты думаешь: «О, окей». А делаешь второй раз — а их уже 11! Откуда? Да пока ты думал, какой-то хитрожопый менеджер успел нового сотрудника на зарплату в 150к впихнуть. Вот эти новые, внезапно появившиеся строки — они и есть фантомы, ёперный театр.

И как со всем этим бороться, спросишь ты?

  • Уровни изоляции транзакций: Это главный костыль, который придумали умные дяди. Есть такие режимы — READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE. Чем строже уровень, тем меньше аномалий он допускает, но зато всё работает медленнее, как говно в проруби. Выбирай, что тебе дороже: скорость или чтобы голова не болела.
  • Блокировки:
    • Пессимистические: Работают по принципу «доверия ебать ноль». Как только ты начинаешь работать с записью, ты её сразу хватаешь и вешаешь замок (SELECT ... FOR UPDATE). Никто другой не подступится, пока ты не отпустишь. Надёжно, но если все будут так делать, можно в дедлоке все повиснуть.
    • Оптимистические: Тут ты всем веришь, как последний лох. Работаешь с копией данных, а когда пришло время сохранять, проверяешь: «А не изменил ли кто эту запись, пока я тут умничал?». Если нет — ок, пишешь. Если да — охуеваешь и начинаешь всё заново. Способ для терпеливых.