2008-10-03 5 views
1

У члена команды возникла проблема со старой внутренней системой, где пользователь, дважды щелкнув ссылку на веб-странице, может вызвать отправку двух запросов из браузера, в результате чего две вставки базы данных одной записи в состояние гонки; последний из которых запускается с ошибкой первичного ключа. Некоторые решения и взломы были предложены и обсуждены:Дважды щелкните разрешения двойной вставки?

  1. Использование Javascript на веб-странице, чтобы смягчить второй щелчок, отключив ссылку на первого щелчка. Это быстрый и простой способ уменьшить возникновение проблемы, но не полностью устранить ее.

  2. Оберните выполнение запроса на стороне филиала в транзакции. Это считается слишком дорогостоящим из-за нагрузки на сервер и уровня блокировки в рассматриваемой таблице.

  3. Поймать исключительное исключение первичного ключа, сброшенное неудавшейся вставкой, определить его как таковое и съесть. Это имеет недостатки (а) блокировки поставщика, необходимость знать нюансы исключений, специфичных для базы данных, и (б) потенциально не регистрировать/обрабатывать законные сбои базы данных.

  4. Расширение №3 путем попытки обновления записи, если вставка не удалась и проверка результата обновления, чтобы гарантировать, что она возвращает 1 запись.

Другие варианты, которые не учитывались? Есть ли плюсы и минусы представленных вариантов, которые были упущены? Что является меньшим из всех зол?

ответ

1

Вам необходимо реализовать шаблон Token Synchronizer.

Как это работает: значение (токен) генерируется на сервере для каждого запроса. Этот же токен должен быть включен в вашу форму представления. При получении запроса токен сервера и токен клиента сравниваются, и если они одинаковы, вы можете продолжать добавлять свою запись. Затем токен серверной части регенерируется, поэтому последующие запросы, содержащие старый токен, не будут выполнены.

Существует более подробное объяснение на полпути вниз this page.

Я не уверен, какую технологию вы используете, но Struts обеспечивает поддержку уровня фрейма для этого шаблона. См. Пример here

5

Поместите уникальный идентификатор на страницу в скрытом поле. Принимайте только один ответ с заданным уникальным идентификатором.

+0

Это добавляет много накладных расходов на стороне сервера - в ферме серверов они бы все, чтобы быть в курсе этого идентификатора, и они все должны синхронизировать и заблокировать его, чтобы не было состояния гонки, если два запроса были сбалансированы на двух разных серверах. – 2008-10-05 16:58:44

+0

Если уникальный идентификатор является основным ключом для вставки базы данных, то ваша целостность базы данных позаботится об этом. – 2008-10-06 01:05:33

0

Кажется, вы уже ответили на свой вопрос; # 1 кажется единственным жизнеспособным вариантом.

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

2

Похоже, что вы можете неправильно использовать запрос GET для изменения состояния сервера (хотя это не обязательно так). В то время как это может быть неприемлемо для вас, следует сказать, что вам следует рассмотреть возможность преобразования ссылки в форму POST.

0

REF Вам необходимо реализовать шаблон Token Synchronizer.

Это для JavaScript/HTML не JAVA