Что такое грязное чтение (Dirty Read) в контексте транзакций СУБД?

Ответ

Грязное чтение (Dirty Read) — это аномалия изоляции транзакций, при которой одна транзакция читает незафиксированные (неподтверждённые) изменения другой, параллельной транзакции. Если та транзакция откатится, первая получит и будет использовать несуществующие данные.

Пример на SQL:

-- Транзакция 1 (изменяет данные)
BEGIN TRANSACTION;
UPDATE accounts SET balance = 1000 WHERE id = 1;
-- Пока транзакция не зафиксирована...

-- Транзакция 2 (читает незафиксированные данные)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- Разрешает грязное чтение
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; -- Получит 1000 (грязные данные)

-- Транзакция 1 откатывается
ROLLBACK; -- balance возвращается к старому значению

-- Транзакция 2 работает с данными, которых никогда не существовало.

Как предотвратить:

  • Установить уровень изоляции транзакции как минимум READ COMMITTED (стандартный уровень в большинстве СУБД).
  • Более строгие уровни: REPEATABLE READ, SERIALIZABLE.

Почему это важно: Грязное чтение нарушает атомарность и согласованность данных, приводя к ошибкам в логике приложения.

Ответ 18+ 🔞

Да ты посмотри, что творят-то, а! Вот сидит себе программист, пьёт кофеек, и тут ему в лоб — грязное чтение. Это ж как в жизни, представляешь? Один чувак на кассе деньги пересчитывает, только что-то там на бумажке накарябал, а второй уже сзади подскочил, в его записи тыркнулся носом и орёт: «О, тысяча есть!» А первый ему: «Да я, блядь, ошибся, сейчас зачеркну!» Но поздно — второй уже побежал эти фантомные бабки тратить. Вот и вся аномалия, ёпта.

Суть, если по-простому: Одна транзакция вычитывает из базы какую-то хуйню, которую вторая транзакция ещё даже не довела до ума и может в любой момент откатить, как невъебенное. А первый-то уже считал и пошёл дальше с этими данными работать. Пиздец, Карл, а не данные.

Вот тебе живой пример на SQL, смотри:

-- Транзакция 1 (наш чувак, который может накосячить)
BEGIN TRANSACTION;
UPDATE accounts SET balance = 1000 WHERE id = 1;
-- Сидит, думает, фиксировать или нет. Пока не решил.

-- Транзакция 2 (любопытная Варвара с обострённым чутьём)
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- Разрешаем себе подглядывать в чужие черновики, блядь
BEGIN TRANSACTION;
SELECT balance FROM accounts WHERE id = 1; -- Ага! Видит эту самую 1000! Хотя это грязные, неподтверждённые данные!

-- А тут наш первый чувак передумал
ROLLBACK; -- balance возвращается к тому, что было. Тысячи как не бывало.

-- И вот вторая транзакция уже строит логику на цифре, которая испарилась в пизду. Красота!

Как от этого спастись, чтобы не было мучительно больно? Да элементарно, Ватсон! Не давай транзакциям лазить по чужим незаконченным делам. Поставь уровень изоляции хотя бы READ COMMITTED (это обычно по умолчанию стоит, кстати). Тогда транзакция будет читать только то, что уже честно зафиксировано. А если хочешь полный параноидальный режим — REPEATABLE READ или SERIALIZABLE, там уж точно никакие грязные чтения не пролезут, хоть ты тресни.

А почему это вообще важно, спросишь? Да потому что вся твоя бизнес-логика, вся эта хитрая арифметика в приложении может посыпаться к ебеням, если будет опираться на фантомы. Получится история про Герасима и Муму, только в мире данных: прочитал что-то, чего не было, и пошёл это топить. А потом совесть заебала.