Атомарные операции 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, указывающий, когда истекает срок условного депонирования. Вы должны установить это значение всякий раз, когда билеты поступают в условное депонирование.

В-третьих, сделка по размещению билетов в условном депонировании должна

  1. заблокировать строку события.
  2. прочитайте колонку доступных билетов. (отменить, если не достаточно доступны)
  3. вставить строку в таблицу условного депонирования
  4. обновите строку события, чтобы уменьшить столбец доступных билетов.
  5. разблокировать строку события.

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

В-пятых, вам нужна операция очистки сделки. Для этого необходимо найти все строки условного депонирования, срок действия которых истек (которые имеют дату истечения в прошлом), и для каждой из них:

  1. заблокировать соответствующую строку события.
  2. читать количество условных билетов из таблицы условного депонирования
  3. удалить строку таблицы условного депонирования.
  4. обновите строку события, чтобы увеличить доступный столбец заявок.
  5. разблокировать строку события.

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

Другие вопросы по тегам