假设我在一家流量很高的网上商店工作。出售的商品需求量很大,但也非常有限。我要确保它们不会被超卖。
目前我有这样的事情:
$order->addProduct($product);
$em->persist($order);
if($productManager->isAvailable($product)){
$em->flush();
}然而,我认为,如果在很短的时间内收到两个订单,这仍然允许超卖一种产品。还有什么其他的可能性,以确保产品绝对不会被超卖?
发布于 2013-09-16 16:26:43
您需要在事务中使用悲观锁。
假设您的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;
}我建议在这里抛出一个例外,因为两个用户同时购买最后一个项目是一个例外的情况。当然,在运行此代码之前,您应该使用某种类型的项计数检查-验证约束或其他什么。因此,如果一个用户已经通过了该支票,但另一个用户在支票之后,在当前用户实际购买之前购买了最后一个项目,这是一种例外情况。
还要注意,您应该在单个HTTP请求期间启动和结束事务。我的意思是,不要在一个HTTP请求中锁定一行,等待用户完成购买,然后才释放锁。如果你想让用户能够把物品放在他们的车里一段时间--就像在现实世界的车里一样--使用其他方法,比如为用户保留一个产品一段时间,方法是仍然减少库存物品的数量,并在超时后将其释放。
发布于 2013-09-16 14:05:03
关于Doctrine2有一个完整的章节讨论并发性,这正是您所需要的。
您需要处理事务自定义查询,并在查询期间锁定您的表。这一切在这里都有解释:事务和并发
https://stackoverflow.com/questions/18829884
复制相似问题