我已经开发了一个用于在线购买我的产品的应用程序。 我的商店中有100件“雨伞”产品。我开发了一个在线购买我的产品的应用程序。 但是同时进行采购会出现问题。
如果同时进行两次购买,那么AvailableQty将错误地更新。假设有两个交易同时发生,并且“购买数量”分别为100和50。理想情况下,第一笔交易(购买数量为100)应该成功,因为我们有100只库存。但是第二次交易应该返回错误,因为库存不足,因为第一次交易的余额为0。(100-100)。但是在上述情况下,两个交易均成功完成,余额现在显示为-50。
当有两个单独的事务时,这将正常工作。但这是同时发生这两个事务的问题。造成此问题的原因是,当并发事务同时检查可用性的条件达到时,由于DB表未使用最新数量更新,因此该条件得到满足。
我该如何纠正?
public bool UpdateStock(int productId, int purchaseQty)
{
using(var db = new MyEntities())
{
var stock = db.Products.Find(productId);
if (stock.AvailableQty >= purchaseQty) // Condition to check the availablity
{
stock.AvailableQty = stock.AvailableQty - purchaseQty;
db.SaveChanges();
return true;
}
else
{
return false;
}
}
}
答案 0 :(得分:1)
这是典型的线程并发问题,可以通过多种方式解决,其中之一是使用简单的lock
语句:
public class StockService
{
private readonly object _availableQtyLock = new object();
public bool UpdateStock(int productId, int purchaseQty)
{
using (var db = new MyEntities())
{
lock (_availableQtyLock)
{
var stock = db.Products.Find(productId);
if (stock.AvailableQty >= purchaseQty) // Condition to check the availablity
{
stock.AvailableQty = stock.AvailableQty - purchaseQty;
db.SaveChanges();
return true;
}
return false;
}
}
}
}
只有一个线程可以获得排他权利来获得对_availableQtyLock
的锁定,这意味着其他线程将不得不等待第一个线程释放对该对象的锁定。
请注意,这是处理并发的最简单(可能是最慢)的方式,还有其他方式可以进行线程同步,例如Monitor
,Semaphore
,快速SlimLock
等...由于很难确定哪一个最适合您的需求,因此您需要进行适当的性能/压力测试,但是建议从最简单开始。
注意:正如其他人在评论中提到的那样,并发问题也可以在数据库级别上完成,这确实会更合适,但是如果您不希望/不能引入任何数据库更改,这将是解决问题的方法去