ダブル挿入解像度をダブルクリックしますか?
-
03-07-2019 - |
質問
チームメンバーが古い社内システムの問題に遭遇し、ユーザーがWebページ上のリンクをダブルクリックすると、ブラウザーから2つのリクエストが送信され、同じレコードの2つのデータベース挿入が発生する可能性があります競合状態。実行する最後のものは、主キー違反で失敗します。いくつかのソリューションとハックが提案され、議論されています:
-
WebページでJavascriptを使用して、最初のクリックでリンクを無効にして2番目のクリックを軽減します。これは、問題の発生を減らすための迅速かつ簡単な方法ですが、完全に排除するわけではありません。
-
トランザクション内のサーバー側でリクエストの実行をラップします。これは、問題のテーブルのサーバー負荷とロックレベルのために、操作のコストが高すぎると見なされています。
-
失敗した挿入によってスローされた主キー例外をキャッチし、それを特定して、それを食べます。これには、(a)ベンダーのロックイン、データベース固有の例外のニュアンスを知る必要があること、および(b)正当なデータベース障害でのログ記録/取引ができないという欠点があります。
-
挿入が失敗した場合にレコードの更新を試み、更新の結果をチェックして、影響を受ける1つのレコードを返すことを確認することによる#3の拡張。
考慮されていない他のオプションはありますか?見落とされたオプションの長所と短所はありますか?すべての悪のうち、どれが小さいですか?
解決
Synchronizer Tokenパターンを実装する必要があります。
仕組み:各リクエストに対して値(トークン)がサーバー上に生成されます。この同じトークンをフォーム送信に含める必要があります。リクエストを受信すると、サーバートークンとクライアントトークンが比較され、それらが同じである場合、レコードを追加し続けることができます。サーバー側トークンが再生成されるため、古いトークンを含む後続のリクエストは失敗します。
中途半端なこのページについて、より詳細な説明があります。
使用しているテクノロジーはわかりませんが、Strutsはこのパターンのフレームワークレベルのサポートを提供します。例こちら
他のヒント
非表示フィールドのページに一意の識別子を配置します。特定の一意の識別子を持つ応答を1つだけ受け入れます。
サーバーの状態を変更するためにGETリクエストを誤用している可能性があります(必ずしもそうではありませんが)。状況によっては適切ではないかもしれませんが、リンクをフォームPOSTに変換することを検討する必要があることを明記する必要があります。
あなたはすでにあなた自身の質問に答えているようです。 #1が唯一の実行可能なオプションのようです。
それ以外の場合は、3つのステップすべてを実際に実行する必要があります。データの整合性はデータベースレベルで処理する必要がありますが、データベースへのラウンドトリップを回避するためのコードでの追加チェック(明示的なトランザクションなど)はパフォーマンスに適している可能性があります。
REF Synchronizer Tokenパターンを実装する必要があります。
これはJavaではなくJavascript / HTML用です