我在asp.net中的锁定无效

时间:2017-06-09 11:17:05

标签: c# asp.net concurrency locking

尽最大努力避免并发问题,即使在实现this锁定方式后仍然会弹出并发错误。

支付提供商有时会非常快速地发送更新(有时甚至会在一秒内发送3次),这使得应用程序很难赶上,因为我们想要做更多的操作。 然后,用户也从支付提供商返回,执行相同的代码。最后,我们有多个请求来自不同的会话,这段代码应该确保一次只能有一个更新。

我的代码:

    public InvoiceModel UpdateInvoicePaymentStatus(PaymentModel payment)
    {

        InvoiceModel invoice = _invoiceRepository.GetByMspId(payment.ExternalOrderId);

        //lock per invoice Id, so we can have multiple different invoice updates, but single updates for one invoice
        object miniLockInvoice = MiniUpdateLock.GetOrAdd(invoice.InvoiceId, new object());
        LoggingManagement.AddOwnErrorObjects("outside lock, for id:" + invoice.InvoiceId, Log.LogLevel.INFO,
            miniLockInvoice);
        lock (miniLockInvoice)
        {
            Log.AddOwnErrorObjects("inside lock, for id:" + invoice.InvoiceId, Log.LogLevel.INFO,
            miniLockInvoice);
            invoice = _invoiceRepository.GetByIdWithCrudRelations(invoice.InvoiceId);//get again inside lock

            //do a lot of logic, send out emails (we don't want to send multiple of course)
            Log.AddOwnErrorObjects("UpdateInvoicePaymentStatus", Log.LogLevel.INFO, invoice, payment);
            base.Update(invoice.InvoiceId, invoice);
            object temp;
            if (MiniUpdateLock.TryGetValue(invoice.InvoiceId, out temp) && temp == miniLockInvoice)
                MiniUpdateLock.TryRemove(invoice.InvoiceId, out temp);
            Log.AddOwnErrorObjects("inside end of lock, for id:" + invoice.InvoiceId + " removed item", Log.LogLevel.INFO,
            temp);
        }
        Log.AddOwnErrorObjects("outside end of lock, for id:" + invoice.InvoiceId, Log.LogLevel.INFO);
        return invoice;

    }

现在在存储库中,最终执行以下代码(通用repo)。现在请记住,正在检索的实体具有timestamp变量以避免并发更新。在ModelToEntity内,时间戳不会更改或更改。

    public virtual void Update(int id, TModel model)
    {
        TEntity entity = GetEntityById(id);
        entity = ModelToEntity(model, entity);
        DbContext.Entry(entity).State = EntityState.Modified;
        DbContext.SaveChanges();
    }

因为你可以看到我在锁内外放了很多日志来追踪发生的事情。

+-----------------------------------------+-----------+----------+
|                  Event                  | session1  | session2 |
+-----------------------------------------+-----------+----------+
| outside lock, for id                    | 3:55:54   | 3:55:55  |
| inside lock, for id:                    | 3:55:54   | 3:56:00  |
| UpdateInvoicePaymentStatus              | 3:56:00   | 3:56:08  |
| inside end of lock, for id: remove item | exception | 3:56:09  |
| outside end of lock, for id:            | exception | 3:56:09  |
+-----------------------------------------+-----------+----------+

为了达到这个目的,我可能会更好地记录毫秒,但是session2session1传递UpdateInvoicePaymentStatus事件之后进入锁定但是在抛出异常之前,也发生在3上:56:00。所以在调用更新数据库方法之前。

锁定无法正常工作或其他内容正在进行我不理解的事情,异常跟踪显示在从此代码块(或路径)中更新实体时发生了这种情况。我在这两个会议之前跟踪了两个会话,他们很好地在另一个更高级别上锁定了对方。那个锁只是一个静态对象。

0 个答案:

没有答案