#node.js #postgresql
#node.js #postgresql
Вопрос:
У меня возникла проблема, когда два почти одновременных запроса (разница в — 10 мс) одного и того же пользователя (непреднамеренно дублированные на стороне клиента) успешно дважды выполняют всю логику прецедентов. Я действительно не могу решить эту ситуацию в коде моего API, поэтому я думал о том, как ограничить user_id
возможность вставки строки в таблицу order
максимум раз в секунду, например.
Я хочу добиться этого: если в таблице order
существует строка с user_id
X и эта строка была создана (вставлена) менее 1 секунды назад, вставка с user_id
X завершится ошибкой.
Это может быть эффективным способом избежать непреднамеренного дублирования запросов со стороны клиента. Потому что я не могу представить ситуацию, когда пользователь мог бы отправить два сложных запроса менее чем за 1 секунду между намеренно. Меня также интересуют любые другие идеи, например, как правильно справляться с подобными ситуациями в API.
Комментарии:
1. Какая колонка, похожая на время, у вас уже есть?
2. Столбец @
row_created
jjanes, который имеет типtimestamp
и значение по умолчаниюnow()
Ответ №1:
С вашей идеей есть одна проблема. Если сервер станет действительно медленным всего на секунду, заказы будут поступать в базу данных с интервалом более одной секунды и будут вставлены.
Я бы рекомендовал создать уникальный идентификатор, например UUID, в интерфейсе и отправить его вместе с запросом. Вы могли бы, например, генерировать новую при каждой загрузке страницы. Затем, если сервер видит, что полученный UUID уже существует в базе данных, заказ пропускается.
Это позволяет избежать любых потенциальных проблем со сроками, но также сохраняет возможность того, что кто-то повторно закажет точно такие же продукты.
Комментарии:
1. Это очень хороший момент, я об этом не подумал. Проблема с вашим решением заключается в том, что в настоящее время я не могу изменить интерфейс (у меня нет доступа к нему), поэтому я думал о том, чтобы разобраться с этим на бэкэнде. Я собираюсь искать возможное решение, но если я не смогу его решить, я попытаюсь предложить изменение интерфейса. Спасибо
Ответ №2:
Вы можете сделать это с ограничением ИСКЛЮЧЕНИЯ. Вам нужно создать свою собственную неизменяемую вспомогательную функцию и использовать расширение.
create extension btree_gist; create function addsec(timestamptz) returns tstzrange immutable language sql as $ select tstzrange($1,$1 interval '1 second') $; create table orders ( userid int, t timestamptz, exclude using gist (userid with =, addsec(t) with amp;amp;) );
Но вам, вероятно, все равно следует изменить интерфейс, чтобы включить маркер проверки, так как в настоящее время он может подвергаться атакам CSRF.
Обратите внимание, что ограничения ИСКЛЮЧЕНИЯ могут быть гораздо менее эффективными, чем ограничения УНИКАЛЬНОСТИ. Кроме того, я не на 100% уверен, что addsec действительно неизменен. Там могут быть странные вещи с високосными секундами или что-то такое, что все портит.
Комментарии:
1. Если это не очень эффективно, то я, вероятно, не буду его использовать, потому что таблица уже большая, и с конкретной таблицей уже были некоторые проблемы с производительностью. Спасибо за предложение решения с использованием ограничения EXCLUDE, потому что у меня пока нет никакого опыта работы с ним, и это выглядит как очень полезная функция. Я поищу дополнительную информацию.