Позвольте двум транзакциям, выполняющим вышеупомянутый код одновременно, называться tx1 и tx2 соответственно.И tx1, и tx2 будут пытаться сначала выполнить
SELECT * FROM PRODUCT WHERE ID = 1 AND STATUS = "AVAILABLE" FOR UPDATE;
Этот запрос также означает получение блокировки строки из набора результатов.Естественно, только одна транзакция может получить его, поэтому другой придется подождать.Например, если tx1 получает блокировку, tx2 будет ждать, пока tx1 не завершит фиксацию и не снимет блокировку.Затем tx2 продолжит работу и выполнит фиксацию, так как он просто устанавливает количество на 0. В результате вышеприведенный подход не будет работать должным образом, потому что в итоге оба пользователя получат сообщение об успешной покупке.Однако если вы хотите сохранить этот подход, вместо того, чтобы напрямую устанавливать значение на ноль, следует уменьшить его на 1 и установить ограничение на столбец, в котором говорится, что его значение не может быть опущено ниже 0. Таким образом, tx2 завершится ошибкой.из-за нарушения ограничений (помните C ACID - Согласованность) и отката, таким образом, второй пользователь получит сообщение о том, что его / ее покупка не удалась.
В качестве альтернативы, если вы не хотите вводить дополнительные ограниченияв этом конкретном примере и просто установить количество напрямую, вы можете использовать оптимистическую блокировку, которая использует прозрачное управление версиями строк, а также дешевле с точки зрения производительности.Таким образом, для продукта с идентификатором 1 (назовем его P) tx1 генерирует новую версию P (P1), а tx2 одновременно генерирует еще одну новую версию P (P2).Когда любой из tx1 и tx2 пытается выполнить фиксацию, система заметит, что существуют новые незафиксированные версии P, P1 и P2, и должна будет утвердить только одну из них.В результате P1 может быть выбран в качестве принятой новой версии P, таким образом, tx1 успешен, и покупка успешна, и P2 отклонен, таким образом, tx2 отменяется и откатывается, и второй пользователь получает сообщение об ошибке о его / ее покупке.Также обратите внимание, что может произойти и обратное, то есть P2 принят и P1 отклонен.
Наконец, в отношении оптимистической и пессимистической блокировки учтите следующее:
- Оптимистическая блокировка предпочтительна, если оценки разработчика приложенийчто конфликты не обязательно должны происходить часто
- Пессимистическая блокировка должна использоваться в противном случае, если вы не хотите частых сбоев из-за частых одновременных обновлений.
Лично я бы выбралпессимистическая блокировка, но фиксирующая вышеупомянутую транзакцию, так как для количеств, превышающих 1, оптимистическая блокировка все равно приведет к прерыванию одной транзакции, в то время как обе могут быть успешно обработаны с использованием пессимистичной, за счет производительности, незначительного значения.
Несмотря на то, что транзакция все еще выполняется, другие пользователи по-прежнему могут видеть ПРОДУКТ доступным, поскольку он еще не зафиксирован, и они также могут переходить к ПЛАТЕ.
В связи с этим онможет быть связано с частотой обновления васэкран сер.Даже если пользователь может приступить к оплате (устаревшие данные на внешнем интерфейсе), бэкэнд должен подтвердить, что пользователь имеет право совершить покупку, и если да, продолжить покупку (все это в одной транзакции).)
Кроме того, если доступно достаточное количество продукта, блокировка ряда продуктов может помешать другим пользователям пытаться купить тот же продукт одновременно.
Это точка пессимистической блокировки, основным результатом которой является падение производительности, но все транзакции могут быть обслужены при условии, что количество не достигает 0. В оптимистической блокировке только 1 будет успешной, а другие -ошибка, побуждающая пользователя повторить попытку покупки.