1

トラフィックの多いオンラインショップで働いているとしましょう。セール中のアイテムは需要が高く、非常に限られています。売り過ぎないようにする必要があります。

現在、私は次のようなものを持っています:

$order->addProduct($product);
$em->persist($order);
if($productManager->isAvailable($product)){
    $em->flush();
}

ただし、非常に短い期間内に 2 つの注文が入った場合、これでも商品の過剰販売が可能になると思います。製品が絶対に売られすぎないようにするために、他にどのような可能性がありますか?

4

2 に答える 2

1

トランザクション内でペシミスティック ロックを使用する必要があります。

Productエンティティに、count残っているアイテムの数を含むフィールドがあるとします。ユーザーがアイテムを購入した後、そのフィールドを減らします。

この場合、悲観的な書き込みロックが必要です。基本的に、悲観的ロックを取得しようとする他のプロセスによって行が読み取られたり更新されたりするのを防ぎます。これらのプロセスは、行をロックしたトランザクションがコミットまたはロールバックによって終了するか、タイムアウトになるまでロックされたままになります。

したがって、トランザクションを開始し、ロックを取得し、十分なアイテムが残っているかどうかを確認し、それらを注文に追加し、アイテムの数を減らして、トランザクションをコミットします。

$em->beginTransaction();

try {
    $em->lock($product, LockMode::PESSIMISTIC_WRITE);

    if ($product->getCount() < $numberOfItemsBeingPurchased) {
        throw new NotEnoughItemsLeftInStock;
    }

    $order->addItem($product, $numberOfItemsBeingPurchased);
    $product->decreaseCount($numberOfItemsBeingPurchased);

    $em->commit();
} catch (Exception $e) {
    $em->rollback();
    throw $e;
}

2 人のユーザーが同時に最後のアイテムを購入することは例外的な状況であるため、ここで例外をスローすることをお勧めします。もちろん、このコードを実行する前に、何らかの項目数チェック (検証制約など) を使用する必要があります。そのため、ユーザーがそのチェックを通過したが、別のユーザーがチェックの、現在のユーザーが実際に購入する前に最後のアイテムを購入した場合、それは例外的な状況です。

また、単一のHTTP リクエスト中にトランザクションを開始および終了する必要があることにも注意してください。つまり、1 つの HTTP リクエストで行をロックせ、ユーザーが購入を完了するのを待ち、その後にのみロックを解除します。現実世界のカートのように、ユーザーがしばらくの間カートにアイテムを保持できるようにしたい場合は、在庫に残っているアイテムの数を減らしてしばらくの間ユーザーのために製品を予約するなど、他の手段を使用してください。その数のアイテムを元に戻すことで、タイムアウト後に解放します。

于 2013-09-16T16:26:43.123 に答える