Я ищу совет о том, как решить проблему одновременного доступа в веб-приложении, построенном на PHP и MySQL.
Пользователи приложения настраивают то, что я называю «коллекцией». Когда настройка завершена, они могут нажать кнопку «Купить сейчас» в PayPal и приобрести коллекцию.
Коллекция состоит из двух отдельных групп вещей: группы виджетов и группы гаджетов. «Настройка» включает в себя выбор того, какие виджеты включить в группу виджетов и какие гаджеты включить в группу гаджетов.
Это своего рода упрощенная схема отношений псевдо-сущностей:
Доступен широкий выбор виджетов и гаджетов, но каждый виджет и каждый гаджет уникальны и могут использоваться только в одной группе за раз.
Проблема заключается в покупке коллекции. Мне нужно убедиться, что когда пользователь нажимает кнопку «Купить сейчас», виджеты, которые он выбрал для своей группы виджетов, и гаджеты, которые он выбрал для своей группы гаджетов, еще не используются в другой платной коллекции.
Представьте, что два человека используют систему одновременно. Каждый из них создает коллекцию *, содержащую одни и те же виджеты и / или гаджеты, и переходит на страницу оформления заказа, где они одновременно нажимают кнопку «Купить сейчас». Выполнение стандартного запроса для проверки того, использовались ли уже выбранные виджеты / гаджеты, было бы ненадежным в этом сценарии, поскольку для обоих пользователей система ответила бы «они доступны», и каждому было бы разрешено приобрести свою коллекцию с «двойным забронированные ресурсы »(как бы).
Поэтому я много читал о транзакциях и блокировках сегодня. Я думаю, что это должно быть связано с моим решением, но у меня много проблем с визуализацией, как это может работать.
На данный момент все, что я могу придумать, это что-то вроде этого: в тот момент, когда нажимается кнопка «Купить сейчас», я запускаю транзакцию, а затем запускаю запрос на блокировку (чтобы предотвратить чтение). а также запись другими сеансами) все строки в таблице виджетов и все строки в таблице гаджетов для каждого элемента, перечисленного в коллекции. После запуска транзакции и установки этих блокировок я мог выполнять запросы, чтобы проверить, использовались ли уже выбранные элементы.
Если бы запросы указывали на то, что предметы не использовались, я позволил бы совершить покупку, а после завершения я бы снял блокировки.
Если бы запросы указывали, что элементы уже использовались, я бы возвратил ошибку и снял блокировки.
Если бы другой пользователь попытался купить коллекцию, содержащую одни и те же виджеты / гаджеты одновременно, он либо получил бы тайм-аут блокировки, и я бы вернул ошибку; или им придется ждать, пока другой сеанс не снимет свои блокировки, а затем — когда их сеанс применяет те же блокировки и запускает те же запросы — они увидят ошибку «уже используется».
Итак, у меня есть два вопроса. Похоже ли это на лучший способ справиться с моей ситуацией. И во-вторых, если да, то выполнимо ли я так, как я описал?
заранее большое спасибо
* которые могут быть сохранены на потом. Я разрешаю пользователям создавать коллекции, содержащие любые виджеты / гаджеты, которые им нравятся — даже те, которые уже используются — исходя из того, что, если они откладывают свою покупку сейчас, то к тому времени, когда они выполнят ее позже, эти ресурсы могут снова стать доступными
да и да. Да, это лучший подход, потому что он самый очевидный и наиболее часто используемый. И да, этот подход работает, я сам использовал его и работал над кодом, написанным другими, кто его использовал.
Старайтесь не проводить анализ, удерживая транзакцию открытой; предварительно протестируйте, запустите транзакцию, установите оптимистичные блокировки, завершите транзакцию, проверьте, какие из них были успешными, и, если некоторые из них уже были заблокированы, снимите только что установленные блокировки. Ваша база данных поблагодарит вас.
Других решений пока нет …