17

我有以下代码执行将单行提交到数据库表(SQL 2008 / .NET 4)

using (var db = new MyDbDataContext(_dbConnectionString))
{
    Action action = new Action();
    db.Actions.InsertOnSubmit(dbAction);
    db.SubmitChanges();
}

通常一切都很好,但偶尔我会遇到以下异常:

System.InvalidOperationException: This SqlTransaction has completed; it is no longer usable.
at System.Data.SqlClient.SqlTransaction.ZombieCheck()
at System.Data.SqlClient.SqlTransaction.Rollback()
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)

SO上有许多类似的问题,但我在阅读后无法找出原因。

这可能仅仅是由于 SQL 超时(在调用后近 25 秒发生异常)吗?或者在这种情况下我应该期待 SQL 超时异常吗?

有谁知道还有什么可能导致这种情况?

4

3 回答 3

12

DataContext.SubmitChanges方法的主体中有以下代码行:

// ...
try
{
    if (this.provider.Connection.State == ConnectionState.Open)
    {
        this.provider.ClearConnection();
    }
    if (this.provider.Connection.State == ConnectionState.Closed)
    {
        this.provider.Connection.Open();
        flag = true;
    }
    dbTransaction = this.provider.Connection.BeginTransaction(IsolationLevel.ReadCommitted);
    this.provider.Transaction = dbTransaction;
    new ChangeProcessor(this.services, this).SubmitChanges(failureMode);
    this.AcceptChanges();
    this.provider.ClearConnection();
    dbTransaction.Commit();
}
catch
{
    if (dbTransaction != null)
    {
        dbTransaction.Rollback();
    }
    throw;
}
// ...

当连接超时时,将catch执行该块并且该dbTransaction.Rollback();行将抛出InvalidOperationException

如果您可以控制代码,则可以像这样捕获异常:

catch
{
    // Attempt to roll back the transaction. 
    try
    {
        if (dbTransaction != null)
        {
            dbTransaction.Rollback();
        }
    }
    catch (Exception ex2)
    {
        // This catch block will handle any errors that may have occurred 
        // on the server that would cause the rollback to fail, such as 
        // a closed connection.
        Console.WriteLine("Rollback Exception Type: {0}", ex2.GetType());
        Console.WriteLine("  Message: {0}", ex2.Message);
    }
    throw;
}
于 2013-05-31T13:49:15.223 回答
3

是的!我遇到过同样的问题。可怕的答案是,SQLServer 有时会在遇到错误时回滚服务器端的事务,并且不会将错误传递回客户端。哎呀!

在 Google Group microsoft.public.dotnet.framework.adonet 上查找“SqlTransaction.ZombieCheck 错误” Colberd Zhou [MSFT] 很好地解释了它。

并查看 aef123 对此SO 帖子的评论

于 2015-04-21T17:51:49.657 回答
2

我可以建议在事务提交之前关闭连接。然后事务被回滚。查看 MSDN 博客上的这篇文章

于 2013-05-25T21:50:35.040 回答