在将 NHibernate 与分布式事务一起使用时,我们遇到了问题。
考虑以下代码段:
//
// There is already an ambient distributed transaction
//
using(var scope = new TransactionScope()) {
using(var session = _sessionFactory.OpenSession())
using(session.BeginTransaction()) {
using(var cmd = new SqlCommand(_simpleUpdateQuery, (SqlConnection)session.Connection)) {
cmd.ExecuteNonQuery();
}
session.Save(new SomeEntity());
session.Transaction.Commit();
}
scope.Complete();
}
有时,当服务器处于极端负载下时,我们会看到以下内容:
- 使用cmd.ExecuteNonQuery执行的查询被选为死锁牺牲品(我们可以在 SQL Profiler 中看到),但没有引发异常。
- session.Save失败并显示错误消息“该操作对事务状态无效。”
- 此后每次执行此代码时,session.BeginTransaction都会失败。前几次,内部异常会有所不同(有时是应该在步骤 1 中引发的死锁异常)。最终它稳定到“服务器未能恢复事务。描述:3800000177”。或“不允许启动新请求,因为它应该带有有效的事务描述符。”
如果不理会,应用程序最终会(在几秒钟或几分钟后)从这种情况中恢复。
为什么第一步没有报死锁异常?如果我们不能解决这个问题,那么我们如何防止我们的应用程序暂时变得不可用呢?
该问题已在以下环境中重现
- Windows 7 x64 和 Windows Server 2003 x86
- SQL Server 2005 和 2008
- .NET 4.0 和 3.5
- NHibernate 3.2、3.1 和 2.1.2
我创建了一个测试夹具,它有时会为我们重现该问题。可在此处获得:http ://wikiupload.com/EWJIGAECG9SQDMZ