2

SQL Server 2008 で実行する N 個のプロセスがあります。いずれかのプロセスが失敗した場合は、他のすべてのプロセスをロールバックする必要があります。

親タスクとN個の子タスクを作成するTPLを使用することを考えていました。これらはすべて transactionScope (IsolationLevel.ReadCommitted) で囲まれていますが、以下の例では、child2がエラーをスローし (customers2 は有効なテーブルではありません)、child1はロールバックされません。

ここで何か間違っていると思いますか?このシナリオを管理する他の方法はありますか?

ここに私のテストコードがあります:

編集 現在のトランザクションで DependClone を使用して、以下のようにコードを変更しました。働いていると思います。

try
        {
            using (TransactionScope mainTransaction = TransactionUtils.CreateTransactionScope())
            {
                var parentTransactionClone1 = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);
                var parentTransactionClone2 = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);

                var parentTask = Task.Factory.StartNew(() =>
                {
                    var childTask1 = Task.Factory.StartNew(() =>
                    {
                        using (TransactionScope childScope1 = new TransactionScope(parentTransactionClone1))
                        {
                            SqlConnection cnn = new SqlConnection("Server=.\\sqlexpress;Database=northwind;Trusted_Connection=True;");
                            cnn.Open();
                            SqlCommand cmd = new SqlCommand("update customers set city ='valXXX' where customerID= 'ALFKI'", cnn);
                            cmd.ExecuteNonQuery();
                            cnn.Close();
                            childScope1.Complete();
                        }

                        parentTransactionClone1.Complete();

                    }, TaskCreationOptions.AttachedToParent);

                    var childTask2 = Task.Factory.StartNew(() =>
                    {
                        using (TransactionScope childScope2 = new TransactionScope(parentTransactionClone2))
                        {
                            SqlConnection cnn = new SqlConnection("Server=.\\sqlexpress;Database=northwind;Trusted_Connection=True;");
                            cnn.Open();
                            SqlCommand cmd = new SqlCommand("update customers2  set city ='valyyy' where customerID= 'ANATR'", cnn);
                            cmd.ExecuteNonQuery();
                            cnn.Close();

                            childScope2.Complete();
                        }

                        parentTransactionClone2.Complete();

                    }, TaskCreationOptions.AttachedToParent);
                });

                parentTask.Wait();
                mainTransaction.Complete();
            }
        }
        catch (Exception ex)
        {
            // manage ex               
        }
public static TransactionScope CreateTransactionScope()
    {
        var transactionOptions = new TransactionOptions();
        transactionOptions.IsolationLevel = IsolationLevel.ReadCommitted;
        transactionOptions.Timeout = TransactionManager.MaximumTimeout;            
        return new TransactionScope(TransactionScopeOption.Required, transactionOptions);
    }
4

2 に答える 2

4

TransactionScope クラスは、現在のスレッドのアンビエント トランザクションを設定します ( Transaction.Currentのみも参照してください。

少なくとも、各タスクが個別のスレッドで実行されると想定する必要があります (TPL では必須ではありませんが)。

関連記事の備考欄の「重要」ボックスを確認してください。スレッド間でトランザクションを共有する場合は、DependentTransaction クラスを使用する必要があります。

個人的には、複数のスレッド間でトランザクションを共有する機能全体が技術的に機能すると確信していますが、スレッドごとに個別のトランザクションを使用する設計を作成する方が簡単であることが常にわかっています。

于 2012-10-23T00:57:56.467 に答える
0

タスク並列ライブラリは、タスクの詳細を独自に把握することはできず、自動的にロールバックすることはありません。できる最も近い方法は、親タスクから、別のタスク child1-rollback を定義することです。これは、child1 が失敗した場合にのみ実行されます。これは、TaskContinuationOption を OnlyOnFailure に設定することで非常にうまく定義できるため、child1 が失敗した場合にのみタスクが実行されます。child2 についても同じことが言えます。

于 2012-10-23T00:56:49.670 に答える