我有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);
}
答案 0 :(得分:4)
TransactionScope类设置当前线程的环境事务(另请参阅Transaction.Current。
您至少应该假设每个任务都在一个单独的线程中运行(尽管这不是TPL的必要条件)。
查看the relevant article的备注部分中的“重要”框 - 如果要在线程之间共享事务,则需要使用DependentTransaction类。
就个人而言,我确信在多个线程之间共享事务的整个工具在技术上是有效的,但是,我总是发现编写一个每个线程使用单独事务的设计更容易。
答案 1 :(得分:0)
任务并行库无法自己弄清楚任务的细节,也不会自动回滚,你可以做的最接近的是你定义的另一个任务child1-rollback的父任务,只有当child1失败了,您可以通过将TaskContinuationOption设置为OnlyOnFailure来非常好地定义,这样任务只有在child1失败时才会执行,同样可以说是关于child2。