13

これが私のトランザクション スコープ ソース コードの現在のアーキテクチャです。3 番目の挿入は .NET 例外 (SQL 例外ではない) をスローし、前の 2 つの挿入ステートメントをロールバックしていません。私が間違っていることは何ですか?

編集: insert2 と insert3 から try/catch を削除しました。また、insert1 の try/catch から例外処理ユーティリティを削除し、"throw ex" を配置しました。それでもトランザクションはロールバックされません。

編集 2: Insert3 メソッドに try/catch バックを追加し、catch ステートメントに「スロー」を追加しました。それでもトランザクションはロールバックされません。

更新:私が受け取ったフィードバックに基づいて、「SqlHelper」クラスは SqlConnection オブジェクトを使用してデータベースへの接続を確立し、次に SqlCommand オブジェクトを作成し、CommandType プロパティを「StoredProcedure」に設定して、SqlCommand の ExecuteNonQuery メソッドを呼び出します。

また、Transaction Binding=Explicit Unbind を現在の接続文字列に追加しませんでした。次のテストで追加します。

public void InsertStuff()
{
    try
    {
        using(TransactionScope ts = new TransactionScope())
        {
            //perform insert 1
            using(SqlHelper sh = new SqlHelper())
            {
                SqlParameter[] sp = { /* create parameters for first insert */ };

                sh.Insert("MyInsert1", sp);
            }

            //perform insert 2
            this.Insert2();

            //perform insert 3 - breaks here!!!!!
            this.Insert3();

            ts.Complete();            
        }
    }
    catch(Exception ex)
    {
        throw ex;
    }
}

public void Insert2()
{
    //perform insert 2
    using(SqlHelper sh = new SqlHelper())
    {
        SqlParameter[] sp = { /* create parameters for second insert */ };

        sh.Insert("MyInsert2", sp);
    }
}

public void Insert3()
{
    //perform insert 3
    using(SqlHelper sh = new SqlHelper())
    {
        SqlParameter[] sp = { /*create parameters for third insert */ };

        sh.Insert("MyInsert3", sp);
    }
}
4

6 に答える 6

29

私も同様の問題に遭遇しました。問題が発生したのは、SqlCommands で使用した SqlConnection が、TransactionScope が作成される前に既に開いていたため、トランザクションとして TransactionScope に登録されなかったためです。

TransactionScope ブロックに入る前に開いている SqlConnection のインスタンスを SqlHelper クラスが再利用している可能性はありますか?

于 2009-03-05T00:24:51.840 に答える
6

Insert3() で例外をキャッチしているように見えるため、呼び出し後にコードが続行されます。ロールバックする場合は、ts.Complete() ステートメントが呼び出されないように、メイン ルーチンの try/catch ブロックまで例外をバブルさせる必要があります。

于 2008-12-04T00:48:57.690 に答える
1

暗黙的なロールバックは、ts.completeを呼び出さずにusingが終了した場合にのみ発生します。Insert3()で例外を処理しているため、例外によってusingステートメントが終了することはありません。

例外を再スローするか、ロールバックが必要であることを呼び出し元に通知します(Insert3()の署名をbool Insert3()に変更しますか?)

于 2008-12-04T00:51:56.267 に答える
1

(例外を飲み込まない編集版に基づく)

操作にはどのくらい時間がかかりますか? それらのいずれかが非常に長時間実行されている場合は、トランザクション バインドの バグ機能が原因である可能性があります。つまり、接続が切り離されている可能性があります。Transaction Binding=Explicit Unbind接続文字列に追加してみてください。

于 2008-12-04T05:05:38.517 に答える
0

ヘルパー クラスが表示されませんが、.NET コードからエラーが発生した場合でも、完全なステートメントを呼び出さないと、トランザクション スコープがロールバックします。私はあなたのために一例をコピーしました。デバッグで何か間違ったことをしている可能性があります。この例では、.net コードにエラーがあり、同様の catch ブロックがあります。

  private static readonly string _connectionString = ConnectionString.GetDbConnection();

    private const string inserttStr = @"INSERT INTO dbo.testTable (col1) VALUES(@test);";

        /// <summary>
        /// Execute command on DBMS.
        /// </summary>
        /// <param name="command">Command to execute.</param>
        private void ExecuteNonQuery(IDbCommand command)
        {
            if (command == null)
                throw new ArgumentNullException("Parameter 'command' can't be null!");

            using (IDbConnection connection = new SqlConnection(_connectionString))
            {
                command.Connection = connection;
                connection.Open();
                command.ExecuteNonQuery();
            }
        }

        public void FirstMethod()
        {
            IDbCommand command = new SqlCommand(inserttStr);
            command.Parameters.Add(new SqlParameter("@test", "Hello1"));


                ExecuteNonQuery(command);

        }

        public void SecondMethod()
        {
            IDbCommand command = new SqlCommand(inserttStr);
            command.Parameters.Add(new SqlParameter("@test", "Hello2"));


                ExecuteNonQuery(command);

        }

        public void ThirdMethodCauseNetException()
        {
            IDbCommand command = new SqlCommand(inserttStr);
            command.Parameters.Add(new SqlParameter("@test", "Hello3"));


                ExecuteNonQuery(command);
            int a = 0;
            int b = 1/a;

        }

    public void MainWrap()
    {


        TransactionOptions tso = new TransactionOptions();
        tso.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
        //TransactionScopeOption.Required, tso
        try
        {
            using (TransactionScope sc = new TransactionScope())
            {
                FirstMethod();
                SecondMethod();
                ThirdMethodCauseNetException();
                sc.Complete();
            }
        }
        catch (Exception ex)
        {
            logger.ErrorException("eee ",ex);

        }
    }

トランザクションをデバッグしたい場合は、このスクリプトを使用してロックや待機ステータスなどを確認できます。

SELECT 
request_session_id AS spid,
CASE transaction_isolation_level 
WHEN 0 THEN 'Unspecified' 
WHEN 1 THEN 'ReadUncomitted' 
WHEN 2 THEN 'Readcomitted' 
WHEN 3 THEN 'Repeatable' 
WHEN 4 THEN 'Serializable' 
WHEN 5 THEN 'Snapshot' END AS TRANSACTION_ISOLATION_LEVEL ,
resource_type AS restype,
resource_database_id AS dbid,
DB_NAME(resource_database_id) as DBNAME,
resource_description AS res,
resource_associated_entity_id AS resid,
CASE 
when resource_type = 'OBJECT' then OBJECT_NAME( resource_associated_entity_id) 
ELSE 'N/A'
END as ObjectName,
request_mode AS mode,
request_status AS status
FROM sys.dm_tran_locks l
left join sys.dm_exec_sessions s on l.request_session_id = s.session_id
where resource_database_id = 24
order by spid, restype, dbname;

例外メソッドを呼び出す前に、2 つのメソッド呼び出しに対して 1 つの SPID が表示されます。

例外前の 2 つの呼び出し

デフォルトの分離レベルはシリアライズ可能です。ロックとトランザクションの詳細については、こちらをご覧ください。

于 2012-04-18T15:35:16.620 に答える
0

で WCF サービス操作を呼び出したときに、同様の問題に遭遇しましたTransactionScope。サービス インターフェイスの「TransactionFlow」属性が原因で、トランザクション フローが許可されていないことに気付きました。したがって、WCF サービス操作は、外側のトランザクション スコープで使用されるトランザクションを使用していませんでした。以下に示すようにトランザクションフローを許可するように変更すると、問題が解決しました。

[TransactionFlow(TransactionFlowOption.NotAllowed)]

[TransactionFlow(TransactionFlowOption.Allowed)]

于 2019-07-29T03:05:40.367 に答える