Как предотвратить повторные запросы от одного пользователя

На сайте пользователям раз в сутки доступен 1 подарок. Интерфейс сайта не позволяет получить более одного подарка в сутки. Так же перед зачислением подарка пользователю идет проверка на возможность его получения путем проверки записей в БД о полученных ранее гифтов в течении суток. Если же отправить сразу два запроса, например через консоль браузера, то сервер на оба запроса отвечает положительно. Видимо после первого запроса запись не успевает добавиться в БД и сервер считает, что ранее пользователь не получал подарки в текущих сутках. Вопрос в том, как запретить повторное получение подарка в течении одних суток. БД mariaDB. Запросы обрабатываются через nginx, php.


Ответы (2 шт):

Автор решения: Akina

Делаем таблицу

CREATE TABLE gifts ( giftdatetime DATETIME DEFAULT CURRENT_TIMESTAMP,
                     giftdate DATE AS (DATE(giftdatetime)),
                     userid BIGINT,
                     UNIQUE (giftdate, userid) );

и просто вставляем в неё идентификатор пользователя:

INSERT INTO gifts (userid) VALUES ({идентификатор пользователя});

Если пользователь сегодня уже участвовал в процессе - возникнет ошибка дублирования уникального ключа, которая легко ловится на клиенте. И никакие "Если же отправить сразу два запроса" это не объедут.

→ Ссылка
Автор решения: Aziz Umarov

Предложенный @Akina вариант валидный, но предложу другой вариант. Генерируйте key для каждого пользователя так, чтоб при множественной попытке вставки результат был всегда одним.

@giftKey = day(serverTime вы можете ключ на сервере) + "_{giftType}" + "_" +"{userId}"

CREATE TABLE gifts ( giftdatetime DATETIME DEFAULT CURRENT_TIMESTAMP,
                     giftKey TEXT, (тут не принципиально)
                     userid BIGINT,
                     UNIQUE (giftKey) ); 

INSERT INTO gifts (@giftKey, @userid) VALUES ({идентификатор пользователя});

В чем принципиальная разница? В случае если вам действительно нужно будет дать приз в этот же день по другой любой причине вы спокойно это сделаете указав причину либо вовсе добавив GUID к ключу если это приз вручаемый несколько раз .... А сделать по той же причине с тем же ключом не удаться.

→ Ссылка