僵尸检查异常 - 该SqlTransaction已经完成,不再可用 - 在简单提交期间

21

我有以下代码,用于将单行提交到数据库表(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超时异常?

还有其他可能导致这种情况的原因吗?


即使您收到了异常,实体是否已保存在数据库中? - Alex Filipovici
3个回答

14

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

4

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

在Google Group microsoft.public.dotnet.framework.adonet上查找"SqlTransaction.ZombieCheck error",Colberd Zhou [MSFT]解释得非常好。

并查看aef123在this SO post上的评论。


2
我建议在事务提交之前先关闭连接,这样事务就会被回滚。可以参考MSDN博客上的这篇文章

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接