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

Chr*_*ris 5 c# sql transactions using rollback

众所周知,当为SQL Connection,Transaction和Command创建“ using”块时,众所周知,与using块关联的连接,事务或命令在离开using块之后会自行处理。

但是,如果在这些块之一中发生异常,例如在命令块中-事务是否会自行回滚,还是开发人员需要在命令“使用”块内进行try catch,然后添加回滚?尝试在事务处理语句中进行尝试?

Joe*_*Joe 6

只要你没有成功调用Commit,事务就会自动回滚。因此,您的 using 块可能看起来像这样,如果在提交之前引发异常,则事务将回滚。

using (IDbConnection connection = ...)
{
    connection.Open();
    using (IDbTransaction transaction = connection.BeginTransaction())
    {
        using (IDbCommand command = ...)
        {
            command.Connection = connection;
            command.Transaction = transaction;
            ...
        }
        ...
        transaction.Commit();
    }
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*oud 2

不保证会被处置。该Dispose(bool)方法SqlTransaction实际上将有条件地回滚:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

如果您注意到的话,只有在this._internalTransaction.Dispose();接到电话时才会发生这种情况。这里的问题是,如果GetBestEffortCleanupTarget抛出异常,它不会被清理。

在您的情况下,只要没有像已经声明的那样抛出异常,您就会落入存在类别Zombied,因此它实际上会Rollback_internalTransaction.Dispose()调用中发出调用。

最后,如果调用它,false它肯定不会被释放。

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

一个有趣的注释是,我认为 MSDN 文档实际上是错误的,因为它对于该Rollback()方法指出:

事务只能从挂起状态回滚(在调用 BeginTransaction 之后,但在调用 Commit 之前)。如果在调用 Commit 或 Rollback 之前处理事务,则事务将回滚。