2

既存のテーブルを作成しようとしてエラーが発生した場合、既存のトランザクションは既にロールバックされているように見えます。

private void CreateSomeThings()
{
    SqlConnection SqlConn = new SqlConnection(ConnectionString);
    SqlConn.Open();

    (new SqlCommand("BEGIN TRANSACTION", SqlConn)).ExecuteNonQuery();

    try
    {
        (new SqlCommand("CREATE TABLE sometable ([some_id] [int] IDENTITY(1,1) NOT NULL)", SqlConn)).ExecuteNonQuery();

        // Create the table again, but carry on by catching the exception
        try
        {
            (new SqlCommand("CREATE TABLE sometable ([some_id] [int] IDENTITY(1,1) NOT NULL)", SqlConn)).ExecuteNonQuery();
        }
        catch (Exception)
        {
        }

        // If another exception is thrown
        (new SqlCommand("bingy bongy boo", SqlConn)).ExecuteNonQuery();

        (new SqlCommand("COMMIT TRANSACTION", SqlConn)).ExecuteNonQuery();
    }
    catch (Exception Ex)
    {
        try
        {
            // ... then this command will fail with "no corresponding BEGIN TRANSACTION"
            (new SqlCommand("ROLLBACK TRANSACTION", SqlConn)).ExecuteNonQuery();
        }
        catch (Exception Ex2)
        {
            throw;
        }
    }
}

何が起こっているのか、その理由を理解したいと思います。トランザクションのロールバックは私の責任であると思います-他のエラーではそうしませんROLLBACK.

4

2 に答える 2

3

SQL Server は一方的にトランザクションのロールバックを決定できます。アプリはトランザクションがまだアクティブかどうかを知ることができないため、これは SQL Server の重大な設計上の欠陥です。どの種類のエラーがロールバックされ、どの種類のエラーがロールバックされないかについては、十分に文書化されていません。たとえば、一意キー違反やその他のデータ エラーがロールバックされないことを覚えていると思います。しかし、他の人はそうします。一部のエラーで接続が終了することさえあります (これはまれであり、設計上の欠陥ではありません)。

最初のエラーでトランザクションを中止し、失敗するかすべてを再試行するようにコーディングすることをお勧めします。これにより、多くの頭痛が解消されます。バッチごとに 1 つのステートメントを実行することをお勧めします。そうしないと、トランザクションの外部で 2 番目のステートメントを実行するリスクがあります。

エラーが発生した後も続行したい場合は、次の 2 つのことを行う必要があります。

  1. ロールバックしないエラーのホワイトリストを作成します。その場合、あなたは続けることができます。
  2. SELECT @@TRANCOUNTトランザクションがまだ有効かどうかを確認します。
于 2013-10-21T13:24:47.883 に答える
0

同じトランザクションに参加させるには、使用しているすべてのコマンドにトランザクション オブジェクトを渡す必要があります。

通常のパターンは次のとおりです。

using (var conn = new SqlConnection("your connection string here"))
{
    SqlTransaction trans = null;
    try
    {
        conn.Open();
        trans = conn.BeginTransaction();

        using (SqlCommand command = new SqlCommand("command text here", conn, trans))
        {
            // do your job
        }
        trans.Commit();
    }
    catch (Exception ex)
    {
        try
        {
            // Attempt to roll back the transaction.
            if (trans != null) trans.Rollback();
        }
        catch (Exception exRollback)
        {
            // Throws an InvalidOperationException if the connection  
            // is closed or the transaction has already been rolled  
            // back on the server.
        }
    }
}
于 2013-10-21T11:16:22.103 に答える