Сценарий
Скажем, у меня есть список кодов ваучеров, которые я даю, я должен убедиться, что, если два человека разместят заказ в одно и то же время, они не получат один и тот же ваучер.
Таблица
CREATE TABLE IF NOT EXISTS `order` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`voucher_id` bigint(20) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `voucher_id` (`voucher_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `order` ADD CONSTRAINT `order_fk` FOREIGN KEY (`voucher_id`) REFERENCES `voucher` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
CREATE TABLE IF NOT EXISTS `voucher` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`code` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Пример данных
INSERT INTO `voucher` (`code`) VALUES ('A'), ('B'), ('C');
Пример запроса
SELECT @voucher_id := v.id FROM `voucher` v LEFT JOIN `order` o ON o.voucher_id = v.id WHERE o.id IS NULL;
INSERT INTO `order` (`voucher_id`) VALUES (@voucher_id);
Вопрос
Я полагаю, что UNIQUE KEY
на voucher_id
в таблице order
предотвратит два ордера с одинаковым voucher_id
, что приведет к ошибке / выдаче исключения, если один и тот же идентификатор ваучера вставлен дважды. Для этого потребуется цикл while, чтобы повторить попытку после сбоя.
Альтернативой является чтение блокировки таблицы ваучеров перед SELECT
и снятие блокировки после INSERT
, гарантируя, что один и тот же ваучер не будет выбран дважды.
Поэтому мой вопрос:
- Что быстрее?
- Цикл while в коде PHP.
- Чтение блокировки таблицы ваучеров.
- Есть ли другой способ?
Редактирование
ALTER TABLE
заказ CHANGE
voucher_id
voucher_id BIGINT(20) UNSIGNED NOT NULL
приведет к сбою INSERT
, если @voucher_id
равно нулю (по желанию, поскольку ваучеров не останется).