如何在nhibernate中复制和重试死锁

fro*_*sty 7 nhibernate deadlock

浏览我的日志,我可以看到我的应用程序容易出现死锁.它们出现在我的应用程序的许多部分中.

1)有没有办法复制这个问题.即:我只在日志中看到过这个.

2)如果事务被锁定,重试的最佳/最简单方法是什么?

3)如果我用try/catch包裹了这个电话.异常类型是什么.

有很多关于这个问题的文章.我总结说,最好的选择是尽可能地尝试缩短交易.我应该改变隔离级别吗?

Ste*_*ger 14

发现死锁

死锁很难找到.如果您知道它们发生的原因,您可以在集成测试中重现它.在实际环境中,您可以使用Profiler来观察死锁.它显示了一个显示死锁形成方式的图表.

重试

你应该扔掉交易并重新开始.任何数据库异常后,NHibernate会话都不同步.

我们在重新启动之前有一段延迟,以避免对数据库造成更多压力.它等待包含随机数的特定时间,以避免并行事务再次同步.

避免死锁

减少锁定时间

如果您使用的是Sql Server,由于其悲观的锁定机制(与Oracle数据库相比),它很容易受到死锁的影响.较新的Snapshot隔离级别与Oracle正在进行的操作类似,可能会在一定程度上解决问题,但直到现在我才开始使用,所以我不能说太多.

NHibernate通过缓存对持久数据的更改并在事务结束时存储它来尽可能地解决问题.但是有一些限制和一些方法可以打破它.

使用标识("自动编号")作为主键可能是最着名的错误.它强制NH在将实体放入会话时插入实体,从而产生整个表的锁(在SQL Server中).

更复杂的问题是冲洗问题.NH需要在执行查询之前刷新更改,以确保一致性.您可以通过设置FlushMode来解决这个Never问题,这可能会导致一致性问题,所以只有在您确切知道自己所做的事情时才能这样做.最佳解决方案是仅使用GetLoad导航到根实体的属性,而不是在事务中间执行查询.

通过这一切,NH能够等待任何插入,更新和删除命令到数据库,直到事务结束.这大大减少了锁定时间,因此也降低了死锁的风险.

避免死锁的一般规则

使用NHibernate时,避免死锁的一般规则也适用.最重要的是:以特定顺序锁定资源,锁定资源不是由一个锁定,而是在开始时锁定所有资源.后者与我上面所说的减少锁定时间相矛盾.这意味着您在事务开始时锁定资源以使其他事务等待直到完成.这可以减少死锁,但也可以减少并行执行.