データがクライアントに到達すると、データはすでに古い/無効であるため、どちらが優れているかは問題ではないと思います。予約の表を表示すると、どの予約が行われているかを大まかに把握するのに役立ちますが、次の 1 秒以内にまったく異なるものになる可能性があります。競合状態を解消したい。まず、優れたアーキテクチャが必要です。
これを行う 1 つの方法は、チケットを「予約」することです [1]。アプリケーションは、一致した基準に基づいて利用可能なチケットを取得するように要求します。この時点で、チケットが利用可能かどうかは既知の事実です。利用可能な場合は、すでに予約済みです。これにより、1 枚のチケットで複数の予約を避けることができます。次の予約 (同じ操作/アクション) では、別のチケットが予約されます。必要に応じて、後でいつでもこのチケットに情報 (チケットの所有者とその情報など) を追加できます。情報が添付されていないチケットは、一定時間後にタイムアウトになり、プールに戻ります。これらのチケットは再度「予約」できます [1]。
[1] 複数の割り当てを避けるには、楽観的ロックを使用します。
質問に答えるために、私は言うでしょうDataReader
。データベース通信を最小限 (負荷とロック) に保つため、更新をできるだけ速く処理できます。1 つを選択しても同時実行性の問題は解決しないことに注意してください。重要なのはトータルソリューションです。
例
要件はわかりませんが、面接の質問なので例を挙げます。これを黄金律とは見なさないでください。しかし、私の頭の先からすると、次のようになります。
(必要な場合) 最初に、予約可能なチケットがシステムに残っていることを示す画面がユーザーに表示されます。接続を開き、リーダーで予約可能なチケットの量を読み取ります。リーダーと接続を閉じます。ユーザーは次の画面に進みます。
SELECT COUNT(*)
FROM [Tickets]
WHERE ([LastReserved] IS NULL OR [LastReserved] <= DATEADD(MINUTE, GETDATE(), @ticketTimeout))
AND [TickedAssignedToUserId] IS NULL;
ユーザーはチケットの x 量を要求し、次の画面に進みます。この時点で、システムは利用可能なチケットが十分にあるかどうかを楽観的ロックでチェックします。(トランザクションを使用して) 接続を開き、次のクエリを実行するだけです。
UPDATE TOP(@numberOfTicketsRequested) [Tickets]
SET [LastReserved]=GETDATE()
WHERE ([LastReserved] IS NULL OR [LastReserved] <= DATEADD(MINUTE, GETDATE(), @ticketTimeout))
AND [TickedAssignedToUserId] IS NULL;
影響を受ける行数は、@numberOfTicketsRequested と同じである必要があります。その場合は、トランザクションをコミットして、そのチケット識別子を取得してください。それ以外の場合は、ロールバックして、利用可能なチケットがもうないことをユーザーに伝えます。この時点で、レコード情報が必要なので、識別子も取得する必要があるかもしれません。
この時点で、ユーザーは@ticketTimeout
自分のユーザーの詳細を入力するための時間を分単位で取得します。正しく実行された場合、次のクエリを実行できます。
UPDATE TOP(@numberOfTicketsRequested) [Tickets]
SET [TickedAssignedToUserId]=@userId
WHERE [TicketId]=@Id AND [LastReserved]=@lastReserved AND [TickedAssignedToUserId] IS NULL;
ユーザーが 10 分以上かかって、他の誰かが同じチケットを再度リクエストした場合、LastReserved
タイムスタンプは変更されています。最初のユーザーが自分の詳細でチケットを予約しようとしたとき、更新は元のLastReserved
タイムスタンプと一致しなくなり、更新は影響を受ける十分な行を表示しません (=ロールバック)。影響を受けた行数と一致する場合、ユーザーはチケットを正常に予約 (=commit) します。
チケット ID 以外のチケット情報がアプリケーションに届いていないことに注意してください。また、ユーザー登録も含めていません。完全なテーブルは渡されず、ロックは最小限に使用されています (2 回の短い更新のみ)。