TransactionScope TransactionAborted Exception - транзакция не откатывается. Должно ли это быть?

(SQL SERVER 2008) Если в TransactionScope возникает ошибка тайм-аута транзакции (.Complete()), ожидаете ли вы откат транзакции?

Обновить:
Ошибка фактически выдается в закрывающей фигурной скобке (т.е..Dispose()), а не.Complete (). Полная ошибка:

The transaction has aborted. System.Transactions.TransactionAbortedException TransactionAbortedException System.Transactions.TransactionAbortedException: The transaction has aborted. ---> System.TimeoutException: Transaction Timeout
   --- End of inner exception stack trace ---
   at System.Transactions.TransactionStateAborted.BeginCommit(InternalTransaction tx, Boolean asyncCommit, AsyncCallback asyncCallback, Object asyncState)
   at System.Transactions.CommittableTransaction.Commit()
   at System.Transactions.TransactionScope.InternalDispose()
   at System.Transactions.TransactionScope.Dispose()

Насколько я могу судить, транзакция не откатывается, и таблицы остаются заблокированными, пока я не произвел KILL против SPID/session_id.

Я использовал DBCC OPENTRAN, чтобы получить самую старую транзакцию, а затем УБИТЬ ее. Я попытался УБИТЬ С СОСТОЯНИЕМ, но получил сообщение о том, что статус недоступен, так как ничего не откатывается. Состояние SPID / session_id в sys.dm_exec_sessions является "спящим". Фрагмент кода:

try
{            
    using (var transaction = new TransactionScope())
    {
        LOTS OF WORK CARRIED OUT WITH LINQ ENTITIES/SubmitChanges() etc.
        transaction.Complete();  //Transaction timeout
    }
    return result;
}
catch (Exception ex)
{
    logger.ErrorException(ex.Message, ex);
    result.Fail(ex.Message);
    return result;
}

ОБНОВИТЬ:
Проблема не полностью решена, но дополнительная информация, если кто-то еще имеет эту проблему.

  1. Я использую LINQ to SQL и в рамках транзакции я вызываю context.SubmitChanges(). Я выполняю много вставок. Профилировщик SQL Server указывает, что для каждой вставки выдается отдельный оператор INSERT.
  2. В процессе разработки, если я сплю поток в течение 60 секунд (тайм-аут TransactionScope по умолчанию равен 60 секундам) ПЕРЕД вызовом SubmitChanges (), я получаю другую ошибку при вызове TransactionScope.Complete() (операция недопустима для состояния транзакции.).
  3. Если я сплю 60 секунд ПОСЛЕ.SubmitChages() и непосредственно перед.Complete (), я получаю "Транзакция прервана - System.TimeoutException: Transaction Timeout"
  4. Однако учтите, что на моем компьютере разработчика не обнаружено открытых транзакций при использовании DBCC opentran - это то, что вы ожидаете, так как ожидаете отката транзакции.
  5. Если затем я добавлю код внизу этого вопроса (извините, я не смог заставить веб-сайт вставить его здесь) в мой файл конфигурации, который увеличивает тайм-аут TransactionScope до 2 минут, все снова начинает работать (исследования показывают, что если это не так) В работе может быть параметр machine.config, который ниже, чем тот, который имеет приоритет).
  6. Хотя это остановит прерывание транзакции из-за характера обновлений, это означает, что блокировки основной бизнес-таблицы могут длиться до 2 минут, поэтому другие команды выбора, использующие тайм-аут SqlCommand по умолчанию, равный 30 секундам, будут иметь тайм-аут. Не идеально, но лучше, чем открытая транзакция, сидящая там и полностью удерживающая приложение.
  7. Несколько дней назад у нас был катастрофический выпуск, который означал, что у нас закончилось дисковое пространство в середине обновления (!), Поэтому мы в конечном итоге использовали функциональность сокращенной базы данных, которая, очевидно, может вызвать проблемы с производительностью после ее использования.
  8. Я чувствую перестройку базы данных и переосмысление некоторых бизнес-функций в будущем...

2 ответа

Решение

Я думаю, что TransactionAbortedException на самом деле тайм-аут. Если это так, вы должны обнаружить, что InnerException TransactionAbortedException является тайм-аутом.

Вы должны быть в состоянии избавиться от этого, убедившись, что время ожидания транзакции больше, чем время ожидания команды.

Попробуйте изменить область транзакции примерно так:

new TransactionScope(TransactionScopeOption.Required, TimeSpan.FromSeconds(60))

А также установите явное время ожидания в вашем контексте. Должно быть что-то вроде:

myContext.CommandTimeout = 30; //This is seconds

Я решаю эту проблему, изменяя "физический файл" machine.config.

1. Вы должны локализовать файл:

  • 32 бита: C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ Config \ machie.config
  • 64 бита: C: \ Windows \ Microsoft.NET \ Framework64 \ v4.0.30319 \ Config \ machine.config

2. Вы должны добавить следующий код:

<system.transactions>
     <defaultSettings timeout="00:59:00" />
</system.transactions>
Другие вопросы по тегам