SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 16.11.2020 22:12:02

asker
Участник
Зарегистрирован: 19.10.2011
Сообщений: 11

Как в решить проблему не согласованного остатка товаров ?

Предположим есть интернет магазин на MySQL, у которого на складе осталось 5 телефонов.
Параллельно приходит 5 пользователей и покупают этот телефон, в результате в базе магазина получается -5.
Я так понимаю можно поставить уровень изоляции serializeble но тогда все будет ужасно тормозить, как по другому можно решить эту проблему ?

Неактивен

 

#2 16.11.2020 22:51:23

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2419

Re: Как в решить проблему не согласованного остатка товаров ?

Сильно зависит от структуры таблиц.

Самый простой и надежный вариант - это блокировать строку нужного товара в транзакции через
select for_update или get_lock или на уровне приложения - тогда остальные будут дожидаться, пока первый купит и в минуса мы не уйдём.

Профи еще советуют делать такие покупки через очередь - то есть все попытки купить закидываются в некоторую очередь, а потом один поток её разгребает, тогда проблема гонки потоков будет решена автоматически.

serializable Вам вряд ли пригодится, и его редко используют.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#3 16.11.2020 22:56:47

rgbeast
Администратор
MySQL Authorized Developer and DBA
Откуда: Москва
Зарегистрирован: 21.01.2007
Сообщений: 3878

Re: Как в решить проблему не согласованного остатка товаров ?

Можно устанавливать уровень изоляции serializable на уровне сессии только для транзакций, связанных с покупкой

Неактивен

 

#4 16.11.2020 23:08:44

asker
Участник
Зарегистрирован: 19.10.2011
Сообщений: 11

Re: Как в решить проблему не согласованного остатка товаров ?

select for_update или get_lock - разве такое есть в MySQL ?


deadka написал:

Сильно зависит от структуры таблиц.

Самый простой и надежный вариант - это блокировать строку нужного товара в транзакции через
select for_update или get_lock или на уровне приложения - тогда остальные будут дожидаться, пока первый купит и в минуса мы не уйдём.

Профи еще советуют делать такие покупки через очередь - то есть все попытки купить закидываются в некоторую очередь, а потом один поток её разгребает, тогда проблема гонки потоков будет решена автоматически.

serializable Вам вряд ли пригодится, и его редко используют.

Неактивен

 

#5 16.11.2020 23:13:58

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2419

Re: Как в решить проблему не согласованного остатка товаров ?

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


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#6 17.11.2020 09:44:34

asker
Участник
Зарегистрирован: 19.10.2011
Сообщений: 11

Re: Как в решить проблему не согласованного остатка товаров ?

deadka написал:

Сильно зависит от структуры таблиц.

Самый простой и надежный вариант - это блокировать строку нужного товара в транзакции через
select for_update или get_lock или на уровне приложения - тогда остальные будут дожидаться, пока первый купит и в минуса мы не уйдём.

Профи еще советуют делать такие покупки через очередь - то есть все попытки купить закидываются в некоторую очередь, а потом один поток её разгребает, тогда проблема гонки потоков будет решена автоматически.

serializable Вам вряд ли пригодится, и его редко используют.

а что значит зависит от структуры таблиц ?

например если есть такая таблица товаров:


CREATE TABLE Product (
 id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
 name varchar(255) NOT NULL,
 quantity int unsigned DEFAULT 0,
 PRIMARY KEY(id)
);
 

Неактивен

 

#7 17.11.2020 13:08:11

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2419

Re: Как в решить проблему не согласованного остатка товаров ?

В прямом смысле - структура данных сильно разная может быть в разных магазинах :-).

Ну вот в Вашем случае можно делать

select НУЖНЫЕ ПОЛЯ for update where id = АЙДИ_ТРЕБУЕМОГО_ТОВАРА;

или через get_lock(АЙДИ_ТРЕБУЕМОГО_ТОВАРА) это реализовывать


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

#8 17.11.2020 18:15:04

LazY
_cмельчак
MySQL Authorized Developer and DBA
Зарегистрирован: 02.04.2007
Сообщений: 845

Re: Как в решить проблему не согласованного остатка товаров ?

asker, а это действительно будет важно на практике?
Для подавляющего большинства интернет-магазинов частота поступления заказов слишком низкая, чтобы это проявилось.
Это два заказа на один и тот же товар должны поступить ориентировочно с интервалом меньше, чем в секунду (грубо говоря).
Если у вас нет хотя бы 1000 заказов в день, вероятность такого события исчезающе мала.
Один случай на 10000 можно разрулить звонком менеджера, это гораздо проще и дешевле, чем наворачивать кружева из транзакций.

Неактивен

 

#9 17.11.2020 21:15:39

asker
Участник
Зарегистрирован: 19.10.2011
Сообщений: 11

Re: Как в решить проблему не согласованного остатка товаров ?

LazY написал:

asker, а это действительно будет важно на практике?
Для подавляющего большинства интернет-магазинов частота поступления заказов слишком низкая, чтобы это проявилось.
Это два заказа на один и тот же товар должны поступить ориентировочно с интервалом меньше, чем в секунду (грубо говоря).
Если у вас нет хотя бы 1000 заказов в день, вероятность такого события исчезающе мала.
Один случай на 10000 можно разрулить звонком менеджера, это гораздо проще и дешевле, чем наворачивать кружева из транзакций.

мне для себя нужно прояснить тк на собеседованиях спрашивают, а я не знал как можно эту проблему решить.

Отредактированно asker (17.11.2020 21:17:45)

Неактивен

 

#10 17.11.2020 23:37:34

deadka
Администратор
Зарегистрирован: 14.11.2007
Сообщений: 2419

Re: Как в решить проблему не согласованного остатка товаров ?

Да, это частый вопрос на собеседованиях.
Ответы ("лучшие" из мне известных )":


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.

Во всех случаях покупка должна идти только через этот фукнционал.

Профи еще рекомендуют вышеупомянутый способ - все попытки покупок класть в очередь, а очередь разбирает один поток. это решит проблему с блокировками автоматически - ибо блокировать не нужно.


Зеленый свет для слабаков, долги отдают только трусы, тру гики работают только в консоли...

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson