【问题标题】:"This SqlTransaction has completed; it is no longer usable."... configuration error?“此 SqlTransaction 已完成;它不再可用。”... 配置错误?
【发布时间】:2011-09-15 13:45:18
【问题描述】:

我已经为此工作了大约一天半,并在网络上搜索了大量的博客和帮助文章。我在 SO 上发现了几个与此错误相关的问题,但我认为它们并不完全适用于我的情况(或者在某些情况下,不幸的是,我无法很好地理解它们以实现:P)。我不确定我能否很好地描述这一点以获得帮助......但这里是:

我们有一个 .NET 应用程序来跟踪我们的资源。具有将资源复制到时间跟踪系统和计费系统的导出功能;这将访问链接到时间和计费数据库的存储过程。

我最近将计费系统数据库移至新服务器(原始服务器:Server 2003 SP2、SQL 2005;新服务器:Server 2008 R2、SQL 2008 R2)。我设置了一个指向 2008 数据库的链接服务器。我更新了存储过程以指向 2008 服务器,然后我收到有关 MSDTC 和 RPC 的错误 (http://www.safnet.com/writing/tech/archives/2007/06/server_myserver.html)。我在链接服务器上启用了“rpc/rpc out”并将 MSDTC 设置为允许网络访问(类似于:http://www.sqlwebpedia.com/content/msdtc-troubleshooting)。

现在,当我尝试运行导出功能时,出现上述情况:“此 SqlTransaction 已完成;它不再可用。”对我来说奇怪的是,当我刚刚运行存储过程(来自 SSMS)时,它说它成功完成。

有人见过这个吗?我错过了配置中的某些内容吗?我不断翻阅相同的页面,唯一发现的是在进行 MSDTC 更改后我没有重新启动(此处提到:http://social.msdn.microsoft.com/forums/en-US/adodotnetdataproviders/thread/7172223f-acbe-4472-8cdf-feec80fd2e64/)。

我可以发布部分或全部存储过程,如果有帮助...请告诉我。

【问题讨论】:

标签: sql stored-procedures sql-server-2008-r2 server-error


【解决方案1】:

我认为此错误消息是由“僵尸交易”引起的。

寻找事务被提交两次(或回滚两次,或回滚并提交等)的可能区域。 .Net 代码是否在 SP 已经提交事务之后提交事务? .Net 代码是否会在遇到错误时回滚,然后尝试在 catch(或 finally)子句中再次回滚?

有可能在旧服务器上从未遇到过错误条件,因此从未遇到过错误的“双重回滚”代码。也许现在您遇到的情况是,新服务器上存在一些配置错误,而现在错误代码正在通过异常处理受到影响。

你能调试错误代码吗?你有堆栈跟踪吗?

【讨论】:

  • 看起来这是在正确的轨道上......我找到了另一个工具(dtctester),我最初的错误是由于配置错误(我以为我已经检查了新服务器上的防火墙......猜猜这就是我假设的结果)。看起来我的新错误与您所说的相符,“EXECUTE 后的事务计数表明缺少 COMMIT 或 ROLLBACK TRANSACTION 语句。先前计数 = 1,当前计数 = 2。”我得再挖掘一点,然后再回复你。
  • 我假设代码中有重复...我在存储过程中注释掉了回滚事务,现在看起来一切正常。我正在等待用户进行测试,但它已经超过了之前出错的地步。 :) 感谢您的意见!
  • 我今天在调试过程中运行了我的代码 300 次,这是我第一次看到这个错误......
【解决方案2】:

我最近在重构新的连接管理器后遇到了这个问题。一个新的例程接受了一个事务,因此它可以作为批处理的一部分运行,问题在于 using 块:

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  using (transaction.Connection)
  {
    using (transaction)
    {
      return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
    }
  }
}

看起来外部使用正在关闭底层连接,因此任何提交或回滚事务的尝试都会抛出消息"This SqlTransaction has completed; it is no longer usable."

我删除了 usings 添加了一个覆盖测试,问题就消失了。

public IEnumerable<T> Query<T>(IDbTransaction transaction, string command, dynamic param = null)
{
  return transaction.Connection.Query<T>(command, new DynamicParameters(param), transaction, commandType: CommandType.StoredProcedure);
}

在事务的上下文中检查任何可能正在关闭连接的东西。

【讨论】:

    【解决方案3】:

    遇到了完全相同的问题,只是找不到正确的解决方案。 希望这对某人有所帮助。

    我有一个带有 EF Core 的 .NET Core 3.1 WebApi。在同时收到多个调用时,应用程序试图同时向数据库添加和保存更改。

    在我的情况下,问题是要保存数据的表没有设置主键。

    当从模型中的 ID 应该是主键的应用程序运行迁移时,EF Core 不知何故错过了。

    我通过打开 SQL Profiler 并看到所有事务已成功提交到数据库(从应用程序)发现了问题,但只创建了一个新行。探查器还显示某种类型的死锁正在发生,但我在探查器的跟踪日志中看不到更多。 经过进一步检查,我注意到“Id”列上缺少主键标识符。

    我从我的应用程序中得到的异常是:

    这个 SqlTransaction 有 完全的;它不再可用。

    和/或

    引发了一个异常,可能是由于瞬态 失败。考虑通过添加来启用瞬态错误恢复能力 'EnableRetryOnFailure()' 到 'UseSqlServer' 调用。

    【讨论】:

    • 我在带有 EF Core 5.06 的 .NET 5 中出现了相同的症状(“此 SqlTransaction 已完成;它不再可用”错误)。但在我的情况下,当我将表从 INT [Id] 的主键更改为 复合键 时,错误就开始了。 (是的,复合键是通过 Fluent API 声明明确定义的。)当对复合键表执行快速操作时,大约 10-20% 的调用会因该错误而失败。 回到单个数字键消除了错误。只是发布这个以防它对任何人有帮助。
    • 这绝对是正确的答案。我从没想过没有主键会触发这个问题,即使列是标识。添加了主键,这个问题就消失了。非常感谢@Danny。
    • 我很高兴我的回答帮助了你@PrashantGupta!
    【解决方案4】:

    我也有同样的问题。发生此错误是因为连接池。当存在两个或多个用户访问系统时,连接池也重用连接和事务。如果第一个用户执行提交,则回滚事务不再可用。

    【讨论】:

    • 这似乎也是我的问题,因为它仅在应用程序中有多个用户时才会发生。任何想法如何解决这个问题?
    【解决方案5】:

    我最近遇到过类似的情况。要在任何 VS IDE 版本中进行调试,请从 Debug(Ctrl + D、E)打开异常 - 选中“Thrown”列的所有复选框,然后在调试模式下运行应用程序。我意识到其中一个表没有正确导入到新数据库中,因此内部 Sql Exception 正在终止连接,从而导致此错误。

    故事的要点是,如果以前的工作代码在新数据库上返回此错误,这可能是数据库架构丢失问题,通过上述调试技巧实现,

    希望对你有帮助, 海德科技

    【讨论】:

    • 感谢您的提示,通过一个真正的巴洛克风格(车轮内的车轮.....)遗留应用程序,这有助于缩小问题的范围
    • 在我的情况下,这是由于嵌入在另一个存储过程中的存储过程调用发生错误。
    【解决方案6】:

    还要检查从您的 .NET 应用程序执行的任何长时间运行的进程是否与数据库相对应。例如,您可能正在调用一个没有足够时间完成的存储过程或查询,这可能会在您的日志中显示为:

    • 执行超时已过期。超时时间过去之前 操作完成或服务器没有响应。

      • 此 SqlTransaction 已完成;它不再可用。

    检查命令超时设置 尝试运行跟踪(分析器)并查看数据库端发生了什么...

    【讨论】:

    • 这是我们的情况。
    【解决方案7】:

    在我的情况下,问题是事务中包含的一个查询引发了异常,即使异常得到“优雅”处理,它仍然设法回滚整个事务。

    我的伪代码是这样的:

    var transaction = connection.BeginTransaction();
    for(all the lines in a file)
    {
         try{
             InsertLineInTable(); // INSERT statement might fail and throw an exception
         }
         catch {
             // notify the user about the error on line x and continue
         }
    }
    
    // Commit and Rollback will fail if one of the queries 
    // in InsertLineInTable threw an exception
    if(CheckTableForErrors())
    {
        transaction.Commit();
    }
    else
    {
        transaction.Rollback();
    }
    

    【讨论】:

      【解决方案8】:

      这是一种检测僵尸交易的方法

      SqlTransaction trans = connection.BeginTransaction();
      
      //some db calls here
      
      if (trans.Connection != null) //Detecting zombie transaction
      {
        trans.Commit();
      }
      

      反编译SqlTransaction类,会看到如下

      public SqlConnection Connection
      {
        get
        {
          if (this.IsZombied)
            return (SqlConnection) null;
          return this._connection;
        }
      }
      

      我注意到如果连接关闭,transOP 将变成僵尸,因此不能Commit。 就我而言,这是因为我在 finally 块内有 Commit(),而连接在 try 块内。这种安排导致连接被释放并被垃圾收集。解决方案是将Commit 放在try 块内。

      【讨论】:

        【解决方案9】:

        对于它的价值,我在以前的工作代码上遇到了这个问题。我在触发器中添加了 SELECT 语句以进行调试测试并忘记删除它们。当其他东西输出到“网格”时,实体框架/MVC 不能很好地发挥作用。确保检查任何恶意查询并将其删除。

        【讨论】:

          【解决方案10】:

          在我的例子中,我有一些代码需要在提交事务后在同一个 try-catch 块中执行。其中一个代码抛出 一个错误然后 try 块将错误移交给它的包含事务回滚的 catch 块。 它将显示类似的错误。比如看下面的代码结构:

          SqlTransaction trans = null;
          
          try{
           trans = Con.BeginTransaction();
          // your codes
          
            trans.Commit();
          //your codes having errors
          
          }
          catch(Exception ex)
          {
               trans.Rollback(); //transaction roll back
              // error message
          }
          
          finally
          { 
              // connection close
          }
          

          希望对某人有所帮助:)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2014-11-17
            • 1970-01-01
            • 2011-03-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多