使用并发交易C#更新数量问题

时间:2018-11-07 08:23:35

标签: c# asp.net entity-framework concurrency transactions

我已经开发了一个用于在线购买我的产品的应用程序。 我的商店中有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;
        }
    }
}

1 个答案:

答案 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的锁定,这意味着其他线程将不得不等待第一个线程释放对该对象的锁定。

请注意,这是处理并发的最简单(可能是最慢)的方式,还有其他方式可以进行线程同步,例如MonitorSemaphore,快速SlimLock等...由于很难确定哪一个最适合您的需求,因此您需要进行适当的性能/压力测试,但是建议从最简单开始。

注意:正如其他人在评论中提到的那样,并发问题也可以在数据库级别上完成,这确实会更合适,但是如果您不希望/不能引入任何数据库更改,这将是解决问题的方法去