Потерянное обновление
Вопрос
Две транзакции в Read Committed одновременно выполняют этот код для одного счёта с балансом 100. Сколько будет на счёте в итоге?
-- в приложении:
BEGIN;
SELECT balance FROM accounts WHERE id = 1; -- получили 100
-- новый баланс = 100 - 30 = 70
UPDATE accounts SET balance = 70 WHERE id = 1;
COMMIT;
Попробуйте сами
Выберите вариант, и откроется разбор.
Показать ответ и разбор
Коротко
Варианты ответа
- 40: база выполнит транзакции строго по очереди
- Одна из транзакций упадёт с ошибкой сериализации
- 70: обе прочитали 100 и записали 70правильный ответ
- 100: обе транзакции откатятся из-за конфликта
Разбор
Это lost update: обе прочитали 100, записали 70, и одно списание потерялось. В Read Committed чтение не ставит блокировку, обе транзакции видят 100, считают в приложении 70 и записывают; второй UPDATE дождётся первого и просто перезапишет значение. Ошибка сериализации возникла бы на Repeatable Read или Serializable. Исправления: атомарный UPDATE ... SET balance = balance - 30, SELECT ... FOR UPDATE или оптимистичная блокировка с версией.
Ответьте сами, а не прочитайте
В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.
Термины по теме
Ещё по теме «Транзакции и изоляция»
- Advisory-блокировки в PostgreSQL
- Как избежать deadlock при переводах
- Взаимоблокировки: как ловить и предотвращать
- Долгая транзакция и раздувание таблиц
- MVCC и VACUUM в PostgreSQL
- VACUUM или VACUUM FULL на проде
- Зачем нужна заморозка и что такое wraparound
- Что делает PostgreSQL при deadlock