维护跨事务的更新顺序以避免死锁

时间:2014-06-12 01:41:32

标签: nhibernate

nhibernate是否有某种方法来维护更新顺序以避免并发事务中的死锁?

例如,如果我有两个事务T1和T2并发执行。我们假设我在一个名为ordered的表中更新了2行,这个名称取消了。

T1

Update order set cancelled = 0 where order_id = 1
Update order set cancelled = 0 where order_id = 2

T2

Update order set cancelled = 0 where order_id = 2  
Update order set cancelled = 0 where order_id = 1 

显然上述情况会导致死锁,如果它们都在同一时间或大约同时执行,因为T1将等待获取第2阶段的锁定,而T2将等待获取第1阶段的锁定。

我的问题是如何确保这些更新的顺序始终相同?这只是通过在两个交易中以相同的顺序更新实体来处理吗?

因此,如果我对实体执行以下操作,我保证更新将以正确的顺序进行吗?

Order order1 = session.Get<Order>(1);
Order order2 = session.Get<Order>(2);

using(ITransaction tran = session.StartTransaction())
{
    order1.Cancelled = 0;
    order2.Cancelled = 0;
    tran.Commit();
}

除此之外,我想知道不同表格的更新。因此,如果我要更新一个名为order的表,并且还有一个名为order_line的表,类似于上面的示例,那么nhibernate是否有一些自动化的方式每次以相同的顺序执行它?

修改

从v4开始,实体框架似乎确实支持这种做法。以下文章解释了这一点:

  

操作顺序
  EF没有暴露出一种控制方式   在SaveChanges期间排序操作。 EF v1确实具体   具有高隔离级别(例如Serializable)的问题   在SaveChanges期间产生死锁。这不是一个很好的宣传   功能,但在EF 4中,我们更改了更新管道以使用更多   不相关CUD操作的确定性排序。这有帮助   确保程序的多个实例将使用相同的顺序   当更新同一组表时,这反过来有助于减少   陷入僵局的可能性。

     

除了SaveChanges,如果你需要有高额的交易   执行查询时隔离,可以手动实现   类似的方法:确保您的应用程序始终访问相同的方法   以相同顺序的一对表,例如使用字母顺序。

以上内容取自here

显然,从2013年1月开始,nhusers小组中也有一个帖子: https://groups.google.com/forum/#!searchin/nhusers/deadlock/nhusers/WVCEJfD3B_w/DGBhHta79cMJ

1 个答案:

答案 0 :(得分:2)

我想我通过挖掘nhibernate代码找到了答案。答案是肯定的,不是。 NHibernate确实能够订购INSERT语句,但您必须通过以下方式在配置文件中手动设置此配置:

<property name="order_inserts">true</property>

这里要注意的一件有趣的事情是,如果adonet.batch_size是&gt;它将默认为true。 0.如果不是> 0你需要手动设置它。

NHibernate中的更新没有相同的功能。底层类支持这一点,但它们没有办法从配置文件中设置它,默认值(C#中的默认布尔值)为false。如果他们将此暴露给配置,则将对订单中的执行更新进行排序。

NHibernate命令INSERTS的方式是按类名,然后是主键。如果他们公开更新订单,它将以相同的方式工作。我希望有人能发现这一点很有见地,因为我确实这样做了。

如果有人感兴趣,支持此功能的基础类是Settings。这是一个名为:

的财产
public bool IsOrderUpdatesEnabled { get; internal set; }