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);
}