“这个SqlTransaction已经完成;它已不再可用。”...配置错误?

时间:2011-06-15 13:54:35

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

我现在已经开展了大约一天半的工作,并在网上搜索了大量的博客和帮助文章。我发现了几个与此错误相关的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/)。

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

10 个答案:

答案 0 :(得分:41)

我认为此错误消息是由于“僵尸交易”造成的。

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

可能在旧服务器上没有遇到错误情况,因此错误的“双回滚”代码从未被命中。也许你现在遇到新服务器上 某些配置错误的情况,现在错误代码被异常处理命中了。

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

答案 1 :(得分:6)

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

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."

我删除了使用添加了覆盖测试,问题就消失了。

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);
}

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

答案 2 :(得分:4)

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

答案 3 :(得分:3)

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

故事的要点是,如果以前工作的代码在新数据库上返回此错误,这可能是数据库模式缺失的问题,通过上面的调试提示实现,

希望它有帮助, HydTechie

答案 4 :(得分:3)

在我的情况下,问题是交易中包含的一个查询引发了异常,即使异常是&#34;优雅地&#34;处理后,它仍然设法回滚整个交易。

我的伪代码就像:

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();
}

答案 5 :(得分:1)

还要检查从.NET应用程序执行的任何长时间运行的进程。例如,您可能正在调用没有足够时间完成的存储过程或查询,这些过程可以在日志中显示为:

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

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

检查命令超时设置 尝试运行跟踪(探查器)并查看数据库端发生的情况......

答案 6 :(得分:1)

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

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

在我的情况下,问题在于保存数据的表没有主键集。

当从应用程序迁移时,以某种方式将模型中的ID作为主键时,EF Core以某种方式丢失了。

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

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

此SqlTransaction具有 完成它不再可用。

和/或

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

答案 7 :(得分:0)

这是一种检测Zombie交易的方法

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。 对于我的情况,这是因为我在Commit()块中有finally,而连接在try块中。这种安排导致连接被处理和垃圾收集。解决方案是将Commit放在try块中。

答案 8 :(得分:0)

就我而言,在同一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
}

希望它将对某人有所帮助:)

答案 9 :(得分:0)

就其价值而言,我已经在以前的工作代码中遇到了这个问题。我在调试测试的触发器中添加了 SELECT 语句,但忘记删除它们。当其他东西输出到“网格”时,实体框架/MVC 效果不佳。请务必检查是否存在任何恶意查询并将其删除。