Атомарные операции MySQL и блокировка таблиц
У меня есть веб-сайт, где пользователи могут покупать билеты, но количество билетов обычно ограничено и идет быстро. Я пытаюсь внедрить систему условного депонирования таким образом, чтобы пользователь мог щелкнуть мышью так, чтобы ему потребовалось х количество билетов, после чего я переведу их в состояние условного депонирования. Это дает им несколько минут для ввода информации о своей кредитной карте и завершения покупки.
У меня есть три соответствующие таблицы: события, билеты и условное депонирование. Строка в таблице событий описывает само событие, включая максимальное количество доступных билетов.
Таблица билетов содержит следующее:
user_id: пользователь, который купил билеты
number_of_tickets: сколько билетов они приобрели
event_id: соответствующее событие
Таблица условного депонирования содержит следующее:
user_id: пользователь в процессе покупки билетов
number_of_tickets: сколько билетов они хотят
event_id: соответствующее событие
В настоящее время я делаю три запроса MySQL, один для определения максимального количества билетов, один для количества проданных билетов и один для количества билетов, уже находящихся в условном депонировании. Затем я рассчитываю:
$remaining_tickets = $max_tickets - $tickets_sold - $tickets_in_escrow;
if ($remaining_tickets >= $tickets_desired)
{
beginEscrow($user_id, $event_id, $tickets_desired);
}
else
{
echo "Error: not enough ticket remain.";
}
Моя проблема в том, что более чем один пользователь может выполнять этот код одновременно. Если бы один пользователь позвонил beginEscrow
после того, как другой пользователь уже прочитал количество билетов уже в условном депонировании, возможно, я перепродал шоу.
Я использую движок InnoDB для своих таблиц, и я прочитал, как заблокировать одну строку с помощью SELECT .... FOR UPDATE
, но я не обновляю ни одной строки. beginEscrow
Функция просто вставит новую строку в таблицу условного депонирования. Я рассчитываю $tickets_in_escrow
читая все строки с правильным идентификатором события и суммируя количество билетов в каждом из них.
Может я об этом все неправильно поняла?
Нужно ли блокировать всю таблицу?
Я не могу быть первым, кто написал систему условного депонирования билетов. Я погуглил себя до смерти, пытаясь найти какой-то учебник по этому виду вещей, но вычеркнул. Любые идеи будут полезны.
Спасибо!
1 ответ
Вы очень близки к своему дизайну, но не совсем там.
Прежде всего, ваша таблица событий должна содержать количество билетов, доступных для вашего мероприятия (в дополнение к тому, что вы там хотите).
Во-вторых, ваша таблица условного депонирования должна иметь столбец DATETIME, указывающий, когда истекает срок условного депонирования. Вы должны установить это значение всякий раз, когда билеты поступают в условное депонирование.
В-третьих, сделка по размещению билетов в условном депонировании должна
- заблокировать строку события.
- прочитайте колонку доступных билетов. (отменить, если не достаточно доступны)
- вставить строку в таблицу условного депонирования
- обновите строку события, чтобы уменьшить столбец доступных билетов.
- разблокировать строку события.
В-четвертых, для завершения продажи необходимо удалить строку условного депонирования и вставить строку проданного билета. Это не сложно
В-пятых, вам нужна операция очистки сделки. Для этого необходимо найти все строки условного депонирования, срок действия которых истек (которые имеют дату истечения в прошлом), и для каждой из них:
- заблокировать соответствующую строку события.
- читать количество условных билетов из таблицы условного депонирования
- удалить строку таблицы условного депонирования.
- обновите строку события, чтобы увеличить доступный столбец заявок.
- разблокировать строку события.
Хитрость заключается в том, чтобы поддерживать количество доступных билетов в правильном порядке, чтобы условия гонки между пользователями не превышали ваше мероприятие.