是否在C#SQL Server调用的“使用”范围内自动回滚?

当您为SQL连接,事务和命令创建“使用”块时,众所周知,使用块关联的连接,事务或命令在您离开使用块后会自行处理.

如果在其中一个块中发生异常,例如在命令块中 – 事务是否会自行回滚,或者开发人员是否需要在命令’using’块内执行try catch,并添加回滚抓住这个尝试的事务声明?

最佳答案 它不能保证被处置. SqlTransaction的Dispose(bool)方法实际上会有条件地回滚它:

// System.Data.SqlClient.SqlTransaction
protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        SNIHandle target = null;
        RuntimeHelpers.PrepareConstrainedRegions();
        try
        {
            target = SqlInternalConnection.GetBestEffortCleanupTarget(this._connection);
            if (!this.IsZombied && !this.IsYukonPartialZombie)
            {
                this._internalTransaction.Dispose();
            }
        }
        catch (OutOfMemoryException e)
        {
            this._connection.Abort(e);
            throw;
        }
        catch (StackOverflowException e2)
        {
            this._connection.Abort(e2);
            throw;
        }
        catch (ThreadAbortException e3)
        {
            this._connection.Abort(e3);
            SqlInternalConnection.BestEffortCleanup(target);
            throw;
        }
    }
    base.Dispose(disposing);
}

如果你注意到,只有当这个._internalTransaction.Dispose();被叫了.这里的问题是,如果GetBestEffortCleanupTarget抛出异常,它将不会被清除.

在你的情况下,只要没有按照已经说明的方式抛出异常,你将属于Zombied类,因此它将在_internalTransaction.Dispose()调用中实际发出一个Rollback调用.

最后,如果用false调用它,肯定不会被处理掉.

现在,除非我真的在这里遗漏了一些东西,否则我对这段代码的脆弱程度感到有些震惊.

一个有趣的说明是,我认为MSDN文档实际上是错误的,因为它声明了Rollback()方法:

The transaction can only be rolled back from a pending state (after BeginTransaction has been called, but before Commit is called). The transaction is rolled back in the event it is disposed before Commit or Rollback is called.

点赞