简体   繁体   中英

using transaction with task parallel library

I have N process to run over SQL Server 2008. If any of the processes fails I need to rollback all the others.

I was thinking to use the TPL creating a parent task and N child task. All of this enclosed with a transactionScope (IsolationLevel.ReadCommitted) but in my example below, the child2 throws an error(customers2 is not a valid table) and the child1 doesn't rolled back.

Am I assuming something wrong here? is there other way to manage this scenario?

Here is my test code:

edit I modified the code as below using the DependClone on the current transaction. I think is working.

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

The TransactionScope class sets the ambient transaction for the current thread (see also Transaction.Current only.

You should at least assume that each task runs in a separate thread (although that is not a necessity with the TPL).

Review the "important" box in the remarks section of the relevant article - if you want to share a transaction between threads, you need to use the DependentTransaction class.

Personally, I am sure that the whole facility to share a transaction amongst multiple threads works technically, however, I have always found it easier to write up a design that uses a seperate transaction per thread.

任务并行库本身无法弄清楚任务的细节,并且它不会自动回滚,你可以做的最接近的是你定义的另一个任务child1-rollback的父任务,只有当child1失败时才会执行,你可以通过指定一个设置为OnlyOnFailure的TaskContinuationOption来很好地定义它,这样任务只有在child1失败时才会执行,同样可以说是关于child2。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM