使用事务与任务并行库

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

TransactionScope类为当前线程设置环境事务(另请参阅Transaction.Current 。

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

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

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

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