Ответ
Грязное чтение (Dirty Read) — это аномалия изоляции транзакций, при которой одна транзакция читает неподтверждённые (незакоммиченные) изменения другой, параллельной транзакции. Если первая транзакция откатывается, вторая прочитает данные, которые никогда официально не существовали в базе, что приводит к несогласованности.
Пример на SQL:
-- Транзакция 1 (T1) -- Транзакция 2 (T2)
BEGIN TRANSACTION;
UPDATE accounts SET balance = 1500
WHERE id = 1; -- Баланс стал 1500
BEGIN TRANSACTION;
SELECT balance FROM accounts
WHERE id = 1; -- T2 читает 1500 (Грязное чтение!)
ROLLBACK; -- T1 откатывается, баланс возвращается к 1000
COMMIT; -- T2 работает с неверным значением 1500
Уровни изоляции, предотвращающие грязное чтение:
READ COMMITTED(и выше, такие какREPEATABLE READ,SERIALIZABLE) в стандарте SQL.- В Java Persistence API (JPA) для этого используется
@Transactional(isolation = Isolation.READ_COMMITTED).
Почему это проблема:
- Нарушает атомарность и согласованность данных.
- Может привести к принятию бизнес-решений на основе несуществующих данных.
Как избежать: Используйте уровень изоляции транзакций не ниже READ COMMITTED, который гарантирует, что транзакция видит только зафиксированные изменения других транзакций.
Ответ 18+ 🔞
Да ты посмотри, что творят-то, а? Вот сидит себе транзакция первая, Т1, значит, и думает: «Ща я этому счёту баланс на 1500 обновлю, пусть порадуется». Обновила, сука, и довольная такая.
А тут, из-за угла, как выскакивает вторая, Т2, хитрая жопа! Глянула на этот самый баланс — о, 1500! — и уже строит планы, как эти виртуальные деньги потратить. «Овердохуища, какой клиент щедрый!» — думает.
И тут БАЦ! Первая транзакция, Т1, такая: «Ой, блядь, я передумала!» И — хрясь! — ROLLBACK. Баланс-то обратно на 1000 откатился, как ни в чём не бывало.
А вторая, Т2, уже с этими фантомными 1500 в голове коммитится и идёт дальше. И что мы имеем? А имеем мы, блядь, грязное чтение (Dirty Read)! Одна начиталась говна, которого в итоге и не было, и теперь вся бизнес-логика поехала, как у мартышлюшки крыша. Приняла решение на основе данных, которые хуй с горы свалились и тут же испарились. Пиздец, да?
Вот тебе наглядный пиздец в коде:
-- Транзакция 1 (T1) -- Транзакция 2 (T2)
BEGIN TRANSACTION;
UPDATE accounts SET balance = 1500
WHERE id = 1; -- Баланс стал 1500
BEGIN TRANSACTION;
SELECT balance FROM accounts
WHERE id = 1; -- T2 читает 1500 (Грязное чтение!)
ROLLBACK; -- T1 откатывается, баланс возвращается к 1000
COMMIT; -- T2 работает с неверным значением 1500
Вот так вот, в рот меня чих-пых! Т2 прочитала незакоммиченный пиздёж от Т1, а потом этот пиздёж взял и рассосался. И сидит Т2 теперь с чувством, будто её ебали в сраку и не кончили.
Как от этого спастись, чтобы не было мучительно больно?
Да хуй сложного! Надо просто не читать чужие черновики, пока они не стали официальной бумажкой. В SQL для этого есть уровень изоляции READ COMMITTED (или любой повыше, REPEATABLE READ, SERIALIZABLE — там вообще жесть, но надёжно). Он как батя строгий: «Не трогай, пока брат свою игрушку до конца не собрал!».
В Java (JPA) это выглядит так, будто ты ставишь блокпост:
@Transactional(isolation = Isolation.READ_COMMITTED)
public void someSensitiveMethod() {
// Тут можно читать, не боясь говна из параллельных транзакций
}
Короче, мораль: если не хочешь, чтобы твоё приложение жило в мире фантомов и галлюцинаций, выставляй изоляцию на READ_COMMITTED как минимум. А то будет как в том анекдоте: «Деньги есть? — Вроде были...».