查看我的日志,我可以看到我的应用程序很容易出现死锁。它们出现在我的应用程序的许多部分。
1)有没有办法复制这个问题。即:我只在日志中看到过这一点。
2)如果事务被锁定,重试的最佳/最简单方法是什么
3)如果我将调用包装在 try/catch 中。异常类型是什么。
关于这个问题有很多文章。我的结论是,最好的选择是尝试尽可能缩短交易时间。我应该更改隔离级别吗?
寻找死锁
僵局很难发现。如果您知道它们发生的原因,您可以在集成测试中重现它。在真实环境中,您可以使用Profiler来观察死锁。它显示了一个图表,显示死锁是如何形成的。
Retry
你实际上应该放弃交易并重新开始。任何数据库异常后,NHibernate 会话都会不同步。
我们在重新启动之前有一个延迟,以避免对数据库造成更大的压力。它等待包含随机数的特定时间,以避免并行事务再次同步。
避免死锁
减少锁定时间
如果您使用 Sql Server,由于其悲观锁定机制(与 Oracle 数据库相反),它非常容易受到死锁的影响。较新的 Snapshot 隔离级别与 Oracle 正在做的类似,可能会在一定程度上解决问题,但我直到现在才使用过,所以我不能说太多。
NHibernate 通过缓存对持久数据的更改并将其存储在事务结束时尽可能地解决了这个问题。但有一些限制和一些打破它的方法。
使用身份(“自动编号”)作为主键可能是最著名的错误。当将实体放入会话中时,它会强制 NH 插入实体,从而产生整个表的锁(在 SQL Server 中)。
解决起来更复杂的是冲洗问题。 NH需要在执行查询之前刷新更改,以确保一致性。您可以通过设置来解决这个问题FlushMode
to Never
,这可能会导致一致性问题,因此只有在您确切知道自己在做什么时才这样做。最好的解决方案是仅使用Get
or Load
或者导航到根实体的属性,而不是在事务中间执行查询。
通过执行所有这些操作,NH 能够等待对数据库的任何插入、更新和删除命令,直到事务结束。这大大减少了锁定时间,因此也降低了死锁的风险。
避免死锁的一般规则
使用 NHibernate 时,避免死锁的一般规则也适用。最重要的是:按一定的顺序锁定资源,不是一个一个地锁定资源,而是从一开始就全部锁定。后者与我上面所说的减少锁定时间是矛盾的。这意味着您在事务开始时锁定资源,以使其他事务等待直到该事务完成。这可能会减少死锁,但也会减少并行执行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)