データがクライアントに到達してから既に古い/無効であるため、どちらの方が良いかは問題ではないと思います。予約の表を表示すると、予約の内容を大まかに把握するのに便利ですが、次の1秒以内に完全に異なる可能性があります。競合状態を解消したい。まずは良い建築が必要です。
これを行う1つの方法は、チケット[1]を '予約'することです。アプリケーションは、一致した基準で利用可能なチケットを取得するように求めます。この時点で、チケットが利用可能かどうかに関する既知の事実。それが利用可能であった場合、すでに予約されていました。これにより、1つのチケットに対する複数の予約が回避されます。次の予約(同じ操作/アクション)により、異なるチケットが予約されます。必要に応じて、このチケットに情報を後から追加することができます(チケットの所有者や情報など)。情報が添付されていないチケットは、一定の時間が経過するとタイムアウトし、プールに戻ります。これらのチケットは再び予約することができます[1]。
[1]複数の割り当てを避けるには、optimistic lockingを使用してください。
質問に答えるために、私はDataReader
と答えます。データベースの通信を最小限に抑える(ロードとロック)ので、できるだけ早く更新を処理できます。 1つずつ別のものを選ぶことは並行性の問題を解決しません。それは重要なトータルソリューションです。
例
私は要件を知りませんが、それは面接の質問ですので、私は例をあげます。これをゴールデンルールとして取ってはいけませんが、私の頭の先端からは次のようなものになります:
(必要な場合)最初に、ユーザーにはチケットが残っている可能性のある画面が表示されます予約済み。接続を開き、リーダで予約可能なチケットの金額を読んでください。リーダーと接続を閉じます。ユーザーは次の画面に進みます。
SELECT COUNT(*)
FROM [Tickets]
WHERE ([LastReserved] IS NULL OR [LastReserved] <= DATEADD(MINUTE, GETDATE(), @ticketTimeout))
AND [TickedAssignedToUserId] IS NULL;
ユーザーはx個のチケットを要求し、次の画面に進みます。現時点では、利用可能なチケットが十分にある場合、システムは楽観的ロックをチェックします。影響を受けた行数が@numberOfTicketsRequestedと同じである必要があります
UPDATE TOP(@numberOfTicketsRequested) [Tickets]
SET [LastReserved]=GETDATE()
WHERE ([LastReserved] IS NULL OR [LastReserved] <= DATEADD(MINUTE, GETDATE(), @ticketTimeout))
AND [TickedAssignedToUserId] IS NULL;
:単純に(!トランザクションとの)接続を開き、次のクエリを実行します。このような場合は、トランザクションをコミットしてチケット識別子を取得します。それ以外の場合はロールバックし、利用可能なチケットがないことをユーザーに伝えます。この時点では、レコード情報が必要なので、識別子も取得することをお勧めします。
この時点で、ユーザは、ユーザの詳細を入力するのに、@ticketTimeout
分を取得します。正しく行わ場合は、次のクエリを実行することができます
UPDATE TOP(@numberOfTicketsRequested) [Tickets]
SET [TickedAssignedToUserId][email protected]
WHERE [TicketId][email protected] AND [LastReserved][email protected] AND [TickedAssignedToUserId] IS NULL;
ユーザーが10分を言う、より長くかかり、他の誰かが再び同じチケットを要求し、その後、LastReserved
タイムスタンプが変更された場合。最初のユーザーがチケットの詳細を予約しようとしたとき、アップデートはもともとのLastReserved
タイムスタンプと一致せず、アップデートでは影響を受ける行(ロールバック)が不十分であると表示されます。影響を受けた行の数と一致する場合、ユーザーはチケットを正常に予約しました(=コミット)。
チケット識別子以外のチケット情報がアプリケーションに到達していないことに注意してください。私はユーザー登録も含んでいません。完全なテーブルは渡されず、ロックは最小限しか使用されていません(2回の短い更新)。
楽観的なロックに関するリンクありがとうございます。そのため、並行性は確実に解決されます。利用可能なチケットを取得しようとするユーザーが多く、チケットを予約しようとしている場合。以来、DataReader接続は常に開いたままです。だから、それはデータベースサーバーの負荷に影響しません。私がDisconnected Architectureを使用している場合、ロックが適用され、データベースサーバーへの負荷も少なくなります。うーん、メモリの問題はそこにあるだろうが、パフォーマンスの問題、データベースサーバーやメモリの問題の負荷になります。 – user2432715
サイドノートとして: 'DataReader'は' IDisposable'を実装しているので、リソース(接続)が接続プールに返されます。現時点では、接続が利用可能になり、スループットが向上するため、他のリーダ/ライトを使用することができます。上記のロックは、従来のロックではないことに注意してください(ロックを解除しないとロックされません)。 – Caramiriel
DataReaderを効率的に使用するには、次の手順を実行します。1.接続を開きます。2. DataReaderを使用してユーザーにデータを表示します。 3.接続を閉じます(ここでリソースは無料になります)。ユーザーはレコードを更新します。 4.再びOoen Connection 5.データリーダーを使用して特定のレコードを更新します。 5.それを閉じます。それに応じてロックが適用されました – user2432715