事务死锁和DBContext

3

你好,我正在使用Entity Framework 4.1的Code First方法。我有一个类MyContainer,它继承了DBContext

我有一个包含7个步骤的流程,每个步骤都会访问许多存储库方法(大约60个)。这个流程根据业务逻辑和用户需求自动或手动执行。为了提高自动流程的性能,我创建了上下文,即MyContainer的对象,一次性传递给所有方法,并在流程结束时丢弃它,这样可以很好地改善性能。但是当手动执行此流程时,同样的方法会被执行,并且容器会在方法本身中创建和丢弃。以下是粗略的代码示例:

public bool UpdateProcess(Process process, MyContainer container = null)
    {
        bool disposeContainer = false;
        if (container == null)
        {
            container = new MyContainer();
            disposeContainer = true;
        }
        var result = SaveProcess(container, process);
        container.SaveChanges();
        if (disposeContainer)
            container.Dispose();
        return result;
    }

自动流程的交易会在过程开始时创建,在过程结束时结束。而手动交易是在 BLL 中的方法中根据用户在 UI 上的操作调用后创建的。现在假设我的自动流程正在运行,同时用户在 UI 上执行了一些操作,我就会收到异常信息:“Transaction (Process ID 65) Was Deadlocked On Lock Resources With Another Process And Has Been Chosen”。当从手动和自动流程同时调用 UpdateProcess() 方法时,我会在 container.SaveChanges() 处得到该异常信息。
如果我在此存储库方法中创建一个事务范围,则会得到帮助。
public bool UpdateProcess(Process process, MyContainer container = null)
 {         bool disposeContainer = false;        
           if (container == null)  
           {             
                  container = new MyContainer();         
                  disposeContainer = true;         
            }
       using(var trans=new TransactionScop(TransactionScopeOption.RequiresNew))        
       { 
          var result = SaveProcess(container, process);
          container.SaveChanges();
          trans.Complete();
       }        
          if (disposeContainer)           
          container.Dispose();        
          return result;   
 } 

它很好地运作了。 然而,我不想在存储库中创建交易,因为交易已经在bll中进行了。

任何帮助将不胜感激。


如果我在每个方法中创建和释放自动进程的容器,而不是在进程开始时创建容器并在进程结束时释放它,则一切都可以正常工作。 - yo chauhan
2
我正在链接一个死锁的定义,如果这是多余的,请原谅。 - Joshua Drake
谢谢您的努力,但它并没有帮助到我的问题。 - yo chauhan
1个回答

2
您遇到的问题(SQL死锁)是大多数非平凡客户端-数据库系统都会遇到的问题,解决起来可能非常困难。
在设计可能发生死锁的代码时,主要原则是假定它们会发生,并设计应用程序以适当地处理它们。通常通过重新提交事务来处理。正如微软在此处所述。

虽然可以将死锁最小化,但无法完全避免。这就是为什么前端应用程序应该设计为处理死锁。

为了最小化您看到的任何死锁,我采取的常规方法如下:
  1. 使用启用了死锁图形的分析器运行分析器以捕获所有死锁
  2. 将所有死锁导出为文本并调查其原因
  3. 检查是否可以通过使用表提示和/或降低事务隔离级别来将其最小化
  4. 查看是否可以通过其他方式将其最小化,例如更改操作顺序
  5. 最后,在完成所有这些操作之后,请确保在与数据库通信时捕获死锁并重新提交事务/查询等。

感谢您的努力。我完全同意您的回复并追踪了死锁问题。但问题在于,如果我不从进程中传递容器,也就是说,如果容器在存储库的每个方法中被创建和处理,那么它可以正常工作,但是当我从开始到结束都传递相同的容器时,就会出现死锁问题。 - yo chauhan
是的 - 这正是我所期望看到的,由于大容器包含许多个单独的事务,很可能其中一种方法正在与另一种方法死锁。从死锁图中,您能确定哪些语句正在发生死锁吗? - Johnv2020

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接