2

我有 N 个进程在 SQL Server 2008 上运行。如果任何进程失败,我需要回滚所有其他进程。

我正在考虑使用 TPL 创建一个父任务和 N 个子任务。所有这些都包含在 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 only。

您至少应该假设每个任务都在单独的线程中运行(尽管这对于 TPL 不是必需的)。

查看相关文章备注部分中的“重要”框- 如果要在线程之间共享事务,则需要使用 DependentTransaction 类。

就个人而言,我确信在多个线程之间共享事务的整个设施在技术上是有效的,但是,我总是发现编写一个每个线程使用单独事务的设计更容易。

于 2012-10-23T00:57:56.467 回答
0

任务并行库无法自行确定任务的详细信息,并且它不会自动回滚,您可以做的最接近的方法是从父任务中定义另一个任务 child1-rollback ,该任务仅在 child1 失败时执行,并且您可以通过将 TaskContinuationOption 设置为 OnlyOnFailure 来很好地定义这一点,因此只有在 child1 失败时任务才会执行,关于 child2 也可以这样说。

于 2012-10-23T00:56:49.670 回答