私はウェブアプリケーションを持っています。その中でフォームを処理するフローは次のようになります。
- 検証
- エラーの一覧表示またはデータの挿入/更新
この特定のシナリオでは、ユーザー登録プロセスを開発していますが、データベース テーブル内の一意の値の可用性を確認することに基づいて、すべての種類のフォームに共通のソリューションを見つけようとしています。
このユーザー登録では、ユーザーのログインは一意である必要があります。検証フェーズでは、アプリケーションはデータベース テーブルでの可用性をチェックし、使用可能な場合は行を挿入します。パスワードやパスワードの確認など、他のフィールドも検証する必要があります。すべての検証は、1 つの HTTP 要求で 1 回行われます。
問題は、アプリケーションがその可用性をチェックした後、最初のユーザーのプロセスがそれを挿入する前に、並列プロセスで別のユーザーによって取得されていないことを確認できないことです。2 人のユーザーが同じミリ秒で同じログインを入力する可能性が非常に低いことは理解していますが、いつか、数千のユーザーが同時に何らかのフォームにデータを入力する別のフォームでこれが起こる可能性があります。
検証にすでに合格している場合、ログインがすでに登録されていることを示すエラー メッセージがユーザーに表示されることはありません。
私が解決しようとしているのは、その可用性を確認した後、1 つのHTTP 要求に挿入する前に、一意の値が使用可能であることを確認することです。最初のユーザーが自分のパスワードとパスワードの確認をいじっていたときに、別のユーザーが同じ一意のログインを登録しても問題ありません。
この問題は、既存の行を使用して簡単に解決できます。SELECT で UPDATE を実行でき、トランザクション中にロックされるからです。しかし、存在しない行で同じことを行うことはできません。それが問題だ。これを解決するにはどうすればよいですか?
ここに私が知っているいくつかの解決策があります。それらのどれが最高かはわかりません。さらに、最善の方法が私に知られているかどうかはわかりませんので、あなたが知っている方法を共有してください.
テーブルのロック
過去にこの問題をテーブルロックで解決していましたが、これが最善の方法であったかどうかはわかりません。プロセスは次のようになりました。
- 書き込み用にテーブルをロックする
- 空室状況を確認する
- エラーを返すか、行を挿入します
- テーブルのロックを解除
テーブル全体をロックすることが最悪の解決策だと言う人もいます。たぶんそうかもしれませんが、それが私が自分で思いついた唯一の方法です。
ロックは 1 つの HTTP リクエストの間だけ維持され、もちろん複数のリクエストの間では維持されません。
エラーを挿入してキャッチする
この方法は、他の人から提案されました。彼らは、その列を一意のインデックス列にし、検証と一意性のチェックを 2 つのフェーズに分けることを提案しました。プロセスは次のようになります。
- データを検証する
- 検証がOKの場合、行を挿入します
- 行の挿入に失敗した場合、一意の値が利用できないというエラーが表示されます
もちろん、列を一意のインデックス列にしました。しかし、これは、データベースの機能を使用して検証時にエラーをスローするという意味ではありません。アプリケーションレベルで行う必要があります。
値の可用性をチェックして挿入するプロセスに例外は何もないため、このシナリオでは例外を試行してキャッチする方法が好きではないため、この方法は好きではありません。私はそれがチェック・アンド・リザーブ・アンド・インサートの方法であるべきだと信じています。ユーザー入力の検証は、例外に基づくべきではないと私は信じています。
間違っているかもしれませんが、これが私の現在の見解です。私が明らかに間違っていると思うなら、その理由を教えてください。