これまでのところ、これにより、少なくともユーザーが複数のセッションでチェックアウトを行うことを防ぐことができます(同じカードを複数回チェックアウトしようとする-ダブルクリックに対処するのに適しています)。
どのようにチェックしますか?標準のSELECT
を使用 またはSELECT ... FOR UPDATE
?手順5に基づいて、アイテムの予約済みの列などを確認していると思います。
ここでの問題は、SELECT ... FOR UPDATE
手順2では、FOR UPDATE
は適用されません。 他のすべてにロックします。 SELECT
にのみ適用されます ed:cart-item
テーブル。名前に基づいて、カート/ユーザーごとに異なるレコードになります。これは、他のトランザクションの進行がブロックされないことを意味します。
上記に続いて、提供した情報に基づいて、SELECT ... FOR UPDATE
を使用していない場合、複数の人が同じアイテムを購入することになります。 ステップ3で。
推奨される解決策
- トランザクションを開始します
-
SELECT ... FOR UPDATE
cart-item
テーブル。
これにより、ダブルクリックが実行されなくなります。ここで選択するのは、ある種の「カート注文」列です。これを行うと、2番目のトランザクションがここで一時停止し、最初のトランザクションが終了するのを待ってから、最初にデータベースに保存された結果を読み取ります。
cart-item
の場合は、必ずここでチェックアウトプロセスを終了してください。 表には、すでに注文されていると記載されています。
-
SELECT ... FOR UPDATE
アイテムが予約されているかどうかを記録するテーブル。
これにより、他のカート/ユーザーがそれらのアイテムを読むことができなくなります。
結果に基づいて、アイテムが予約されていない場合は、続行します:
-
UPDATE ...
手順3のテーブルで、アイテムを予約済みとしてマークします。その他のINSERT
を実行します sおよびUPDATE
sあなたも必要です。 -
支払う。支払いサービスが支払いが機能しなかったと言った場合は、ロールバックを発行します。
-
成功した場合は、支払いを記録します。
-
トランザクションのコミット
手順5と7の間に失敗する可能性のあること(メールの送信など)を行わないようにしてください。そうしないと、トランザクションがロールバックされた場合に、記録されずに支払いが行われる可能性があります。
ステップ3は、2人(またはそれ以上)の人が同じアイテムを注文しようとしないようにするための重要なステップです。 2人が試してみると、2人目の人は、最初の人の処理中にWebページが「ハング」することになります。次に、1つ目が終了すると、2つ目は「予約済み」列を読み取り、誰かがそのアイテムをすでに購入したというメッセージをユーザーに返すことができます。
取引中の支払いかどうか
これは主観的なものです。一般に、複数の人が一度にデータベースと対話することからロックアウトされないように、トランザクションをできるだけ早く閉じる必要があります。
ただし、この場合、実際には彼らに待たせたいのです。それはどれだけの時間の問題です。
支払い前にトランザクションをコミットすることを選択した場合は、進行状況を中間テーブルに記録し、支払いを実行してから、結果を記録する必要があります。支払いが失敗した場合は、更新したアイテム予約レコードを手動で元に戻す必要があることに注意してください。
SELECT ...FORUPDATE存在しない行
テーブルのデザインに、以前にSELECT ... FOR UPDATE
する必要のある行を挿入する必要がある場合は、警告が表示されます。 :行が存在しない場合、他のトランザクションもSELECT ... FOR UPDATE
であれば、そのトランザクションによって他のトランザクションが待機することはありません。 同じ存在しない行。
したがって、必ずSELECT ... FOR UPDATE
を実行してリクエストをシリアル化してください。 あなたが最初に存在することがわかっている行に。次に、SELECT ... FOR UPDATE
まだ存在する場合と存在しない場合がある行。 (SELECT
だけを実行しようとしないでください SELECT
を実行した時点ではなく、トランザクションが開始された時点で行の状態を読み取るため、存在する場合と存在しない場合がある行。 。したがって、SELECT ... FOR UPDATE
存在しない行については、最新の情報を取得するために実行する必要があります。他のトランザクションが待機することはないことに注意してください。)