Вы можете добавить вторую таблицу, которая содержит все используемые коды. Таким образом, вы можете использовать уникальное ограничение в таблице назначений, чтобы убедиться, что один код не назначен дважды.
CREATE TABLE `used_codes` (`usage` INTEGER PRIMARY KEY auto_increment,
`id` INTEGER NOT NULL UNIQ, -- This makes sure, that there are no two assignments of one code
allocated_at datetime NOT NULL);
Вы добавляете идентификатор использованного кода в таблицу used_codes
и запрашиваете, какой код вы использовали впоследствии. Когда эти две операции выполняются в одной транзакции, вся транзакция завершится неудачно при второй попытке использовать один и тот же код.
Я не тестировал следующий код, вы можете его настроить.
Также вам необходимо убедиться, что ваш сервер соответствует требованиям для транзакций .
-- There are changes which have to be atomic, so don't use autocommit
SET autocommit = 0;
BEGIN TRANSACTION
INSERT INTO `used_codes` (`id`, `allocated_at`) VALUES
(SELECT `id` FROM `promotion_codes`
WHERE NOT `id` in (SELECT `id` FROM `used_codes`)
LIMIT 1), now());
SELECT `code` FROM `promotion_codes` WHERE `id` =
-- You might need to adjust the extraction of insertion ID, since
-- I don't know if parallel running transactions can see the maximum
-- their maximum IDs. But there should be a way to extract the last assigned
-- ID within this transaction.
(SELECT `id` FROM `used_codes` HAVING `usage` = max(`usage`));
COMMIT
Вы можете использовать возвращенный код, если транзакция прошла успешно. Если там, где более одного процесса запущено для использования одного и того же кода, только один из них завершился успешно, в то время как остальные завершаются неудачно с ошибками вставки о дублированной строке. В вашем программном обеспечении вам необходимо различать ошибку дублируемой строки и другие ошибки и повторно выполнять оператор ошибок дублирования.