Что произойдет с полем quantity в таблице products, если два пользователя одновременно попытаются купить один и тот же товар?

«Что произойдет с полем quantity в таблице products, если два пользователя одновременно попытаются купить один и тот же товар?» — вопрос из категории Базы данных, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Без дополнительных механизмов синхронизации может возникнуть состояние гонки (race condition), приводящее к некорректному уменьшению количества товара (например, вместо уменьшения на 2, уменьшится на 1). Это происходит из-за последовательного чтения и обновления значения разными транзакциями.

Пример проблемного сценария:

  1. Транзакция A и B читают quantity = 10.
  2. A вычисляет новое значение: 10 - 1 = 9 и обновляет строку.
  3. B, основываясь на старом значении (10), вычисляет 10 - 1 = 9 и также обновляет строку.
  4. Итог: quantity = 9, хотя должно быть 8.

Решение: Использовать атомарные операции или пессимистические блокировки.

  • Атомарное обновление в одном запросе:
    UPDATE products SET quantity = quantity - 1 WHERE id = 123 AND quantity > 0;
  • Пессимистическая блокировка (SELECT FOR UPDATE):
    BEGIN;
    SELECT quantity FROM products WHERE id = 123 FOR UPDATE; -- Блокировка строки
    -- Проверка quantity > 0 и логика приложения
    UPDATE products SET quantity = quantity - 1 WHERE id = 123;
    COMMIT;
  • Оптимистическая блокировка (версионирование): Добавить поле version. Каждое обновление проверяет, не изменилась ли версия с момента чтения.