MySQL - предотвращение двойного бронирования - PullRequest
1 голос
/ 12 ноября 2009

Я пытаюсь найти лучший способ остановить двойное «бронирование» в моем заявлении.

У меня есть таблица уникальных идентификаторов, каждый из которых может быть продан только один раз.

Моя текущая идея состоит в том, чтобы использовать транзакцию, чтобы проверить, доступны ли выбранные продукты, если они затем вставляются в столбец «статус», что он «зарезервирован» вместе со вставкой «время обновления», то если пользователь продолжает платить Я обновляю статус до «продано».

Каждые 10 минут я проверяю задание cron на наличие «status» = «зарезервировано», которое было обновлено более 10 минут назад, и удаляю такие строки.

Есть ли лучший способ? Я никогда не использовал транзакции (я только что услышал слово), так что если кто-то может объяснить, как я это сделаю, это будет туз.

Ответы [ 3 ]

5 голосов
/ 12 ноября 2009

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

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

Ваш подход (столбец статуса) верен, но я бы реализовал его иначе. вместо столбца состояния добавьте два столбца: reserved_by и reserved_ts.

  • при резервировании товара, установите reserved_by на первичный ключ пользователя или сеанса и reserved_ts на now().
  • при поиске незарезервированных продуктов ищите те, у которых reserved_ts нулевой или более 10 минут. (на самом деле я бы выглядел на пару минут старше, чем вы сказали бы своему пользователю, чтобы избежать возможных условий гонки.)
  • Работа cron для очистки старых резервирований становится ненужной.
3 голосов
/ 12 ноября 2009

То, что вы пытаетесь сделать со своим «зарезервированным» статусом, - это, по сути, эмуляция транзакционного поведения. Вам гораздо лучше позволить эксперту (mysql) справиться с этим за вас.

Прочитайте общие сведения о транзакциях базы данных , а затем , как их использовать в MySQL . Они не слишком сложны. Не стесняйтесь задавать вопросы о них здесь позже, и я постараюсь ответить.

Редактировать : Теперь, когда я думаю о ваших требованиях ... возможно, только с использованием транзакций базы данных - не лучшее решение - иметь множество открытых транзакций и ожидать действий пользователя для фиксировать транзакции, вероятно, не очень хороший выбор дизайна. Вместо этого продолжите то, что вы делали с дизайном "status" = "reserved", но используйте транзакции в базе данных, чтобы установить значение "status", чтобы гарантировать, что строка не "зарезервирована" двумя пользователями одновременно .

0 голосов
/ 12 ноября 2009

Вам не нужно иметь никакого дополнительного состояния, чтобы сделать это.

Чтобы избежать грязных чтений , вы должны установить для базы данных уровень изоляции , который позволит избежать их. А именно, ПОВТОРЯЕМЫЙ ЧИТАЙТЕ или СЕРИАЛИЗИРУЕМЫМ.

Вы можете установить уровень изоляции в глобальном масштабе или для конкретного сеанса. Если все ваши сеансы могут нуждаться в изоляции, вы можете также установить ее глобально.

Как только уровень изоляции установлен, вам просто нужно использовать транзакцию , которая запускается до того, как вы SELECT, и, необязательно, ОБНОВЛЯЕТ статус, если SELECT обнаружил, что он еще не зарезервирован.

...