Задавайте вопросы, мы ответим
Вы не зашли.
Страниц: 1
Предположим есть интернет магазин на MySQL, у которого на складе осталось 5 телефонов.
Параллельно приходит 5 пользователей и покупают этот телефон, в результате в базе магазина получается -5.
Я так понимаю можно поставить уровень изоляции serializeble но тогда все будет ужасно тормозить, как по другому можно решить эту проблему ?
Неактивен
Сильно зависит от структуры таблиц.
Самый простой и надежный вариант - это блокировать строку нужного товара в транзакции через
select for_update или get_lock или на уровне приложения - тогда остальные будут дожидаться, пока первый купит и в минуса мы не уйдём.
Профи еще советуют делать такие покупки через очередь - то есть все попытки купить закидываются в некоторую очередь, а потом один поток её разгребает, тогда проблема гонки потоков будет решена автоматически.
serializable Вам вряд ли пригодится, и его редко используют.
Активен
Можно устанавливать уровень изоляции serializable на уровне сессии только для транзакций, связанных с покупкой
Неактивен
select for_update или get_lock - разве такое есть в MySQL ?
deadka написал:
Сильно зависит от структуры таблиц.
Самый простой и надежный вариант - это блокировать строку нужного товара в транзакции через
select for_update или get_lock или на уровне приложения - тогда остальные будут дожидаться, пока первый купит и в минуса мы не уйдём.
Профи еще советуют делать такие покупки через очередь - то есть все попытки купить закидываются в некоторую очередь, а потом один поток её разгребает, тогда проблема гонки потоков будет решена автоматически.
serializable Вам вряд ли пригодится, и его редко используют.
Неактивен
asker написал:
select for_update или get_lock - разве такое есть в MySQL ?
https://dev.mysql.com/doc/refman/5.7/en … n_get-lock
https://dev.mysql.com/doc/refman/5.7/en … reads.html
Активен
deadka написал:
Сильно зависит от структуры таблиц.
Самый простой и надежный вариант - это блокировать строку нужного товара в транзакции через
select for_update или get_lock или на уровне приложения - тогда остальные будут дожидаться, пока первый купит и в минуса мы не уйдём.
Профи еще советуют делать такие покупки через очередь - то есть все попытки купить закидываются в некоторую очередь, а потом один поток её разгребает, тогда проблема гонки потоков будет решена автоматически.
serializable Вам вряд ли пригодится, и его редко используют.
а что значит зависит от структуры таблиц ?
например если есть такая таблица товаров:
Неактивен
В прямом смысле - структура данных сильно разная может быть в разных магазинах :-).
Ну вот в Вашем случае можно делать
Активен
asker, а это действительно будет важно на практике?
Для подавляющего большинства интернет-магазинов частота поступления заказов слишком низкая, чтобы это проявилось.
Это два заказа на один и тот же товар должны поступить ориентировочно с интервалом меньше, чем в секунду (грубо говоря).
Если у вас нет хотя бы 1000 заказов в день, вероятность такого события исчезающе мала.
Один случай на 10000 можно разрулить звонком менеджера, это гораздо проще и дешевле, чем наворачивать кружева из транзакций.
Неактивен
LazY написал:
asker, а это действительно будет важно на практике?
Для подавляющего большинства интернет-магазинов частота поступления заказов слишком низкая, чтобы это проявилось.
Это два заказа на один и тот же товар должны поступить ориентировочно с интервалом меньше, чем в секунду (грубо говоря).
Если у вас нет хотя бы 1000 заказов в день, вероятность такого события исчезающе мала.
Один случай на 10000 можно разрулить звонком менеджера, это гораздо проще и дешевле, чем наворачивать кружева из транзакций.
мне для себя нужно прояснить тк на собеседованиях спрашивают, а я не знал как можно эту проблему решить.
Отредактированно asker (17.11.2020 21:17:45)
Неактивен
Да, это частый вопрос на собеседованиях.
Ответы ("лучшие" из мне известных )":
1)
begin;
$amount = db->query(select * from product where product_id = НУЖНЫЙ_АЙДИ for update) ;
if $amount > сколько_нужно_купить {
осуществляем покупку
update product set amount = amount - СКОЛЬКО_НАДО_купить where product_id = НУЖНЫЙ_АЙДИ
} else {
не осуществляем, соотв. записи
}
commit;
2) вместо select for update get_lock(НУЖНЫЙ_АЙДИ)
3) вместо select for update select in exclusive mode.
Во всех случаях покупка должна идти только через этот фукнционал.
Профи еще рекомендуют вышеупомянутый способ - все попытки покупок класть в очередь, а очередь разбирает один поток. это решит проблему с блокировками автоматически - ибо блокировать не нужно.
Активен
Страниц: 1