Как правильно заблокировать таблицу MYSQL в параллельной среде?
Всем привет, я борюсь над тем, как обеспечить согласованность следующей операции в этом сценарии: мы разрабатываем портал бронирования, где вы можете записаться на курсы. Каждый курс имеет ряд прямых бронирований: когда доступные бронирования закончатся, пользователи все еще могут подписаться, но попадают в список ожидания.
Итак, вот такая ситуация: например, давайте представим, что курс имеет 15 свободных мест, и я делаю свой заказ. По простой логике, когда я сделал свой заказ, система должна решить, нахожусь ли я в списке прямого бронирования (один из 15 доступных слотов) или в списке ожидания. Чтобы сделать это, мы должны подсчитать, если общее количество прямых резерваций меньше общего количества доступных резерваций, что-то вроде этого в псевдокоде:
INSERT new_partecipant IN table_partecipants; (my_id) = SELECT @@IDENTITY; (total_reservations_already_made) = SELECT COUNT(*) FROM table_partecipants WHERE flag_direct_reservation=1; if total_reservations_already_made <= total_reservations_available then UPDATE table_partecipants SET flag_direct_reservation=1 WHERE id=my_id
Вопрос в том, как я могу управлять параллелизмом, чтобы быть уверенным, что две подписки управляются правильно? Если у меня осталось только одно бронирование и два пользователя подают заявку одновременно, я думаю, что результат операции подсчета может дать один и тот же результат для обоих запросов и вставить обоих пользователей в список.
Каков правильный способ блокировки (или аналогичной процедуры), чтобы быть уверенным, что если пользователь запускает процедуру подписки, то никто не сможет выполнить ту же задачу до завершения запроса?
Что я уже пробовал:
На данный момент мы просто подсчитываем и обновляем данные, как описано выше, но в случае высоких параллельных запросов я думаю, что это может привести к неправильным подпискам.
Michael_Davies
Вы читали руководство MySQL по блокировке таблиц?
https://dev.mysql.com/doc/refman/5.7/en/lock-tables.html
PGagliardi
Конечно, но у меня нет практического опыта в этом деле,и я не знаю рисков, кроме того, я читал, что блокировка таблиц не является рекомендуемой процедурой, учитывая тот факт, что наилучшей практикой является использование транзакций (но на самом деле я не представляю, как определить транзакцию в этом случае).
ZurdoDev
Я бы не стал пытаться запирать столы. Я бы объединил их в одно утверждение. Я не занимаюсь MySql, поэтому я могу показать вам, как будет выглядеть Sql и MySql будет похож.
Вставить в таблицу 1 (field1, flag_direct_reservation)
SELECT @field1, CASE WHEN (SELECT COUNT (*) FROM sometable) > (SELECT COUNT(*) FROM othertable) ТОГДА 1 ИНАЧЕ 0 КОНЕЦ
PGagliardi
Звучит неплохо! Но можете ли вы привести рабочий пример также и для оператора UPDATE?
Попробовать это:
Обновление таблицы mytable настроить подписку = (случай, когда (выбрать количество(*) из таблицы mytable, где поле=идентификатор_курса) &ГТ; max_reservations тогда 0 иначе 1 конец) где ID=id_subscription
но я получил следующую ошибку:
"Вы не можете указать целевую таблицу "mytable" для обновления в предложении from".
ZurdoDev
Вам придется поискать его в MySql, извините.