处理NHibernate事务错误

Zub*_*ber 6 nhibernate deadlock database-deadlocks

我们的应用程序(使用NHibernate和ASP.NET MVC)在进行压力测试时会抛出大量的NHibernate事务错误.主要类型是:

  1. 交易未连接或已断开连接
  2. 行被另一个事务更新或删除(或未保存的值映射不正确)
  3. 事务(进程ID 177)在锁资源上与另一个进程发生死锁,并被选为死锁牺牲品.重新运行该交易.

有人可以帮助我找出异常1的原因吗?我知道我必须处理代码中的其他异常.有人能指出我可以帮助我以有效的方式处理这些错误的资源吗?

问:我们如何管理会话和交易?

答:我们正在使用Autofac.对于每个服务器请求,我们创建一个新的请求容器,其中包含容器生命周期范围内的会话.在激活会话时,我们开始交易.请求完成后,我们提交事务.在某些情况下,交易可能很大.为简化起见,每个服务器请求都包含在事务中.

Hen*_*rik 1

看看这个线程: http://n2cms.codeplex.com/Thread/View.aspx ?ThreadId=85016

基本上它所说的这个异常的可能原因是:

2010-02-17 21:01:41,204 1警告 NHibernate.Util.ADOExceptionReporter - System.Data.SqlClient.SqlException:数据库“databasename”的事务日志已满。要了解日志中的空间无法重用的原因,请参阅 sys.databases 中的 log_reuse_wait_desc 列

由于事务日志的大小与事务期间完成的工作量成正比,因此也许您应该考虑将事务边界放在命令处理程序“处理”事务写入部分的命令之间。然后,您可以使用会话 #X 加载您想要改变的状态,改变它并提交它,所有这些都作为 #X 中的一个工作单元。

至于读取方面,您可能会拥有另一个读取数据的 ISession#Y;这个 ISession 可用于在 RepeatableRead 或类似 Futures 功能的东西中批量读取,并且可以简单地从缓存中读取(尽管它确实是一个拐杖)。这样做可能会帮助您从并非如此的“错误”中恢复;活锁、死锁和受害者事务。

每个请求使用事务的问题是,您的 ISession 在您工作时获取大量簿记数据,所有这些数据都是事务的一部分。因此,数据库将数据(角色、列、表等)标记为参与事务,导致等待图跨越“实体”(在数据库意义上,而不是 DDD 意义上),而这些实体实际上并不是事务的一部分您的应用程序所执行的命令的事务边界。

根据记录(其他人在谷歌上搜索此内容),Fabio 有一篇文章涉及处理数据层的异常。引用他的一些代码;

public class MsSqlExceptionConverterExample : ISQLExceptionConverter
{
  public Exception Convert(AdoExceptionContextInfo exInfo)
  {
      var sqle = ADOExceptionHelper.ExtractDbException(exInfo.SqlException) as SqlException;
      if(sqle != null)
      {
          switch (sqle.Number)
          {
              case 547:
                  return new ConstraintViolationException(exInfo.Message,
                      sqle.InnerException, exInfo.Sql, null);
              case 208:
                  return new SQLGrammarException(exInfo.Message,
                      sqle.InnerException, exInfo.Sql);
              case 3960:
                  return new StaleObjectStateException(exInfo.EntityName, exInfo.EntityId);
          }
      }
      return SQLStateConverter.HandledNonSpecificException(exInfo.SqlException,
          exInfo.Message, exInfo.Sql);
  }
}
Run Code Online (Sandbox Code Playgroud)
  • 547 是约束冲突的异常编号。
  • 208 是 SQL 中无效对象名称的异常编号。
  • 3960 是由于更新冲突而中止的快照隔离事务的异常编号。

因此,如果您遇到了像您所描述的那样的并发问题;请记住,它们将使您的 ISession 无效,并且您必须像上面那样处理它们。

您可能正在寻找的部分内容是 CQRS,其中您有单独的读取端和写入端。这可能会有所帮助:http://abdullin.com/cqrs/,http : //cqrsinfo.com

总结一下;您的问题可能与您处理交易的方式有关。另外,尝试跑步select log_wait_reuse_desc from sys.databases where name='MyDBName',看看它会给你带来什么。