Задача, TransactionScope и хранимая процедура SQL Server - PullRequest
1 голос
/ 06 сентября 2011

Мне нужно обновить таблицу данных, для которой я отправляю данные в формате XML.Моя хранимая процедура имеет транзакцию, чтобы прервать операцию, если что-то пойдет не так.Но количество записей, которые я должен обновить, достаточно велико, и XML достигает 35 МБ +.Это только в разработке, и данные в реальном времени будут еще больше.

Чтобы справиться с этим, я хочу обновить, отправляя данные порциями, то есть я буду отправлять 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;

Но я получаю исключение, что транзакция уже была прервана.

Что мне придется сделатьсделать для обновления в одной транзакции, потому что мне нужно откатить любые изменения, если какой-либо кусок не может обновиться должным образом.

РЕДАКТИРОВАТЬ: - Я использую new TransactionScope(TransactionScopeOption.Required,new TimeSpan(2,0,0)), как предложено Ридом Копси, но все еще получаюошибка System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.TimeoutException: Transaction Timeout даже после одного вызова базы данных, который завершился через 2-3 секунды.

только для одного вызова

Ответы [ 2 ]

1 голос
/ 06 сентября 2011

Вам нужно дождаться завершения задач, прежде чем звонить 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
    }
}
0 голосов
/ 25 июня 2013

Вы когда-нибудь задумывались о безопасности потоков?Интересно, что внутри PushDataAsync.

TransactionScope не работает через потоки из коробки.Он использует локальное хранилище потоков.Тот факт, что область принадлежит одному потоку, явно указан в документации.

Не уверен, действительно ли вы движетесь в правильном направлении, но посмотрите на DependentTransaction, если вы хотите координироватьтранзакция в нескольких потоках: http://msdn.microsoft.com/en-us/library/system.transactions.dependenttransaction.aspx

...