2009-05-29 110 views
1

我有一个更新我的业务实体的例程。更新涉及大约6个不同的表格。所有的命令都在一个事务中执行。如何避免这些死锁?

最近,我需要将一些代码添加到从数据库访问查找表的例程中。查找代码已经存在于另一个业务对象中,所以我使用了该业务对象。例如:

Using tr As DbTransaction = myConnection.BeginTransaction() 
    ExecuteCommand1(tr) 
    ExecuteCommand2(tr) 
    If myLookupTable.GetLookupTable().FindById(id).HasFlagSet Then 
     ExecuteCommand3(tr) 
    End If 
End Using 

但是,查找表业务对象挂起/死锁。我认为这是因为它没有引用原始程序正在使用的事务。

经过一番研究,我试图把查找表逻辑放在自己的事务中,将IsolationLevel设置为ReadUncommitted。这给了我想要的结果。但是,经过进一步的研究,如果我已经正确实施了这个方法,我现在会进行二次猜测。

假设我的查找表对象对活动事务的引用不可用,那么我所描述的是否被认为是最佳实践?我觉得我可能会错过一些东西。

+0

command1或command2是否在查找可执行文件? – 2009-05-29 00:18:46

回答

3

如果您在事务处理过程中正在进行读操作,那么您应该在事务上下文中执行该操作,而不是使用其他事务和脏读操作。幸运的是,有一个简单的解决方案:使用.Net TransactionScope对象而不是使用ADO.Net事务对象。 ADO.Net代码非常明智,并且会征用您在此事务中的所有操作,包括您的其他业务组件读取。只要确保您的业务对象不会打开不同的连接,就会导致尝试将现有事务升级为分布式事务,并将新连接加入其中。

另一种方法是在每次调用时传递SqlConnection/SqlTransaction对,但是在代码中随处传播的可怕程度非常糟糕。

0

如果是我,我会重写逻辑,所以我不必做一个未提交的阅读。

0

避免死锁的黄金法则是始终在每个事务中以相同的顺序获取表锁。因此,看看其他事务中的代码,看看他们使用表锁的顺序;那么请确保您在交易中使用相同的订单。

0

显然,您的查找尝试访问专门被事务tr锁定的行。如果您使用readuncommitted事务或在查找查询中使用WITH(NOLOCK),您将看到所有未发生的可能正在发生的事务以及影响查找逻辑的更改。所以我不太确定这是多么的可取。

我认为最好找到一种方法来确保您的查找查询参与当前事务,如果您需要在该事务中执行查找。如果所有这些操作都要在同一个线程中执行,那么您可以做的一件事是在创建线程本地存储时将事务对象存储在线程本地存储中,并使GetLookupTable方法为线程本地存储检查事务对象,如果存在是一个事务集,您可以从该事务对象获取连接。否则,您创建一个新的连接。通过这种方式,您的查询将成为该事务的一部分,并且应该运行其逻辑,而不会被当前事务阻塞,从而阻止当前事务,从而导致死锁。