处理NHibernate事务错误

时间:2010-08-03 07:34:52

标签: nhibernate deadlock database-deadlocks

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

  1. 交易未连接或已断开连接
  2. 行被另一个事务更新或删除(或未保存的值映射不正确)
  3. 事务(进程ID 177)在锁资源上与另一个进程发生死锁,并被选为死锁牺牲品。重新运行交易。
  4. 有人可以帮助我找出异常1的原因吗? 我知道我必须处理代码中的其他异常。有人能指出我可以帮助我以有效的方式处理这些错误的资源吗?

    Q值。我们如何管理会话和交易?

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

4 个答案:

答案 0 :(得分: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'已满。要找出答案   为什么日志中的空间无法重用,   请参阅中的log_reuse_wait_desc列   sys.databases中

由于事务日志的大小与事务期间完成的工作量成比例,因此您可能需要考虑将事务边界放在命令处理程序“处理”事务的写入部分上。然后,您将使用会话#X加载您希望变异的状态,将其变异并提交,这些都是#X中的一个工作单元。

关于事物的读取方面,你可能会有另一个读取数据的ISession #Y;这个ISession可以用来批量读取例如RepeatableRead或与Futures功能类似的东西,可以简单地从缓存中读取(它确实是一个拐杖)。这样做可能有助于您从“错误”中恢复;活锁,死锁和受害者交易。

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

对于记录(其他人在谷歌上搜索),Fabio有a post处理来自数据层的异常处理。引用他的一些代码;

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);
  }
}
  • 547是约束冲突的例外号码。
  • 208是SQL中无效对象名称的异常编号。
  • 3960是因更新冲突而中止的快照隔离事务的异常编号。

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

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

总结一下;您的问题可能与您处理交易的方式有关。另外,请尝试运行select log_wait_reuse_desc from sys.databases where name='MyDBName'并查看它为您提供的内容。

答案 1 :(得分:1)

这个帖子有一个解释: http://groups.google.com/group/nhusers/browse_thread/thread/7f5fb68a00829d13

简而言之,由于某些错误,数据库可能会自行回滚事务,因此当您尝试稍后回滚事务时,它已经回滚并处于僵尸状态。这往往会隐藏回滚的实际原因,因为你看到的只是一个TransactionException而不是实际上首先触发回滚的异常。

除了记录它并试图找出导致潜在错误的原因之外,我认为你无法做很多事情。

答案 2 :(得分:0)

答案 3 :(得分:0)

我知道这篇文章有一段时间了,假设你修复它,但好像你有NHibernate ISession的线程共享问题,这不是线程安全的。基本上1个线程正在启​​动一个事务而另一个正在尝试关闭它导致各种混乱。