Вопрос с собеседования · Базы данных
Что такое потерянное обновление и как его избежать?
JuniorТранзакции и изоляция
Ещё спрашивают так:
- Зачем нужен SELECT FOR UPDATE?
- Почему два одновременных запроса портят счётчик?
Коротко
Два запроса одновременно читают одно значение (остаток 10), каждый вычисляет новое (10 − 1 = 9) и записывает — в итоге 9 вместо 8: одно обновление потеряно. Защита: атомарное обновление в одном запросе (UPDATE ... SET stock = stock - 1 WHERE stock > 0), пессимистическая блокировка строки (SELECT ... FOR UPDATE внутри транзакции) или оптимистическая с версией (UPDATE ... WHERE version = ?).
- Схема «прочитать в приложении — посчитать — записать» без защиты небезопасна
- Атомарный UPDATE — самый простой и быстрый вариант
- Уровень изоляции Read Committed по умолчанию от этого не защищает
А ещё Проверка: число затронутых строк — 0 значит, условие не выполнилось
Подробно
Плохо:
stock = db.fetch("SELECT stock FROM items WHERE id = 1")
db.execute("UPDATE items SET stock = %s WHERE id = 1", stock - 1)
Хорошо:
UPDATE items SET stock = stock - 1 WHERE id = 1 AND stock > 0;
Или в транзакции:
BEGIN;
SELECT stock FROM items WHERE id = 1 FOR UPDATE;
-- проверка в приложении
UPDATE items SET stock = 9 WHERE id = 1;
COMMIT;Что хотят услышать
- Сценарий потерянного обновления.
- Атомарный UPDATE.
- SELECT FOR UPDATE и оптимистическая версия.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Прочитать значение в приложении, вычесть и записать — это безопасно при любой нагрузке
- ✗Достаточно добавить индекс на колонку, которую обновляют
- ✓Параллельные записи затирают друг друга; спасают атомарный UPDATE, FOR UPDATE или версия строки
- ✗Транзакция видит незафиксированные данные другой; спасает переход с Read Uncommitted на Read Committed
Связанные вопросы
Партнёр платформы
Разбор собеседования
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.