9

SQL 接続、トランザクション、およびコマンドの「using」ブロックを作成すると、using ブロックが関連付けられている接続、トランザクション、またはコマンドは、using ブロックを離れた後に適切に破棄されることがよく知られています。

ただし、これらのブロックのいずれかで例外が発生した場合、たとえばコマンド ブロックで - トランザクションは独自にロールバックされますか、それとも開発者はコマンド 'using' ブロック内で try catch を実行し、ロールバックを追加する必要がありますか?この試行のキャッチ内のトランザクション ステートメントは?

4

2 に答える 2

3

Commit を正常に呼び出さない限り、トランザクションは自動的にロールバックされます。したがって、using ブロックは次のようになります。コミットの前に例外がスローされると、トランザクションはロールバックされます。

using (IDbConnection connection = ...)
{
    connection.Open();
    using (IDbTransaction transaction = connection.BeginTransaction())
    {
        using (IDbCommand command = ...)
        {
            command.Connection = connection;
            command.Transaction = transaction;
            ...
        }
        ...
        transaction.Commit();
    }
}
于 2013-08-22T19:22:08.503 に答える
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);
}

this._internalTransaction.Dispose();気がつけば、それは呼び出された場合にのみ発生します。ここでの問題はGetBestEffortCleanupTarget、例外がスローされた場合にクリーンアップされないことです。

あなたの場合、既に述べたように例外がスローされない限り、存在のカテゴリに分類されるZombiedため、実際にRollback呼び出しで呼び出しを発行し_internalTransaction.Dispose()ます。

最後に、これが呼び出されfalseた場合、ほとんどの場合、破棄されません。

さて、ここで本当に何かが欠けていない限り、このコードがどれほど脆弱であるかに少しぞっとします。

興味深いことに、MSDN のドキュメントは、メソッドについて次のように述べているため、実際には間違っていると思います。Rollback()

トランザクションは、保留状態からのみロールバックできます (BeginTransaction が呼び出された後、Commit が呼び出される前)。Commit または Rollback が呼び出される前に破棄された場合、トランザクションはロールバックされます。

于 2013-08-22T19:21:32.370 に答える