【问题标题】:Task, TransactionScope and SQL Server Stored Procedure任务、TransactionScope 和 SQL Server 存储过程
【发布时间】:2011-09-06 15:44:24
【问题描述】:

我必须更新一些我以 XML 形式发送数据的 DataTable。如果出现问题,我的存储过程具有中止操作的事务。但是我必须更新的记录数量很大,XML 达到 35 mb+。它只是在开发中,实时数据将会更大。

为了处理这个问题,我想通过分块发送数据来更新,也就是说,我将一次发送数百条记录的 XML。我尝试使用Task 库像这样并行更新数据库。

var ret=0;
using(var ts = new TransactionScope(TransactionScopeOption.Required,
                                                      new TimeSpan(2,0,0))
{
    try
    {
        for(some condition)
        {
            get chunk of records
            generate xml
            create new task and call routing to push data to db
            var t = create new task and call routing to push data to db
            tasks.Add(t);
        }

        Task.WaitAll(tasks.ToArray());
        ts.Complete();
        foreach(var t in tasks)
            ret += t.Result;
    }
    catch(Exception ex)
    {
        //log exception and show user message
    }
}
return ret;

但是我得到了事务已经被中止的异常。

我必须做些什么才能在单个事务中完成更新,因为如果任何块无法正确更新,我必须回滚任何更改。

编辑:- 我按照 Reed Copsey 的建议使用 new TransactionScope(TransactionScopeOption.Required,new TimeSpan(2,0,0)),但即使在 2-3 秒内完成对数据库的一次调用后,仍然出现错误 System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.TimeoutException: Transaction Timeout

只有一个电话

【问题讨论】:

  • WaitForAll 不是 Task 上的方法 - 你能把你的真实代码放在适当的位置吗?
  • @Reed Copsey 真正的代码在办公室 :D 方法是Task.WaitAll

标签: c# sql-server-2008 stored-procedures task transactionscope


【解决方案1】:

您需要等到任务完成后再致电ts.Complete()。这应该看起来更像:

using(var ts = new TransactionScope())
{
    try
    {
        List<Task> tasks = new List<Task>();

        for(some condition)
        {
            // get chunk of records
            // generate xml
            // create new task and call routing to push data to db
            var task = PushDataAsync(theData); // make the task
            tasks.Add(task); // Keep a reference in a collection
        }

        // Wait until all tasks are done, so you can complete the transaction...
        // If any task raises an exception, you'll get an AggregateException here
        Task.WaitAll(tasks.ToArray());

        ts.Complete();
    }
    catch(Exception ex)
    {
        //log exception and show user message
    }
}

【讨论】:

  • @TheVillageIdiot:这应该可行 - 你是 TransactionScope 超时吗?这会导致它在您进行处理时中止,可能......
  • 我明天会得到确切的例外并更新问题。但如果TransactionScope 超时,我有什么选择?
  • @TheVillageIdiot: 有一个构造函数可以让你指定一个TimeSpan 的超时时间——你可以让它足够长:)
  • 我已经用更多细节编辑了我的问题。尝试了 TransactionScope 构造函数,时间跨度为 2 小时,但仍然出现异常。
【解决方案2】:

您是否考虑过线程安全?我想知道 PushDataAsync 里面是什么。

TransactionScope 不适用于开箱即用的线程。它在内部使用线程本地存储。范围属于单个线程这一事实在文档中被明确指出。

不确定您是否真的朝着正确的方向前进,但如果您想跨多个线程协调事务,请查看 DependentTransaction:http://msdn.microsoft.com/en-us/library/system.transactions.dependenttransaction.aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 2012-12-29
    • 2011-11-22
    相关资源
    最近更新 更多