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 для получения самой старой транзакции, а затем KILL. Я попробовал KILL WITH STATUS, но получил сообщение о том, что статус не доступен, поскольку ничто не откатывается назад. Состояние 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;
}

UPDATE:
Проблема не полностью решена, но дополнительная информация должна быть у кого-либо еще.

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

      

Ответы

Ответ 1

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

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

Попробуйте изменить область транзакций на что-то вроде этого:

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

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

myContext.CommandTimeout = 30; //This is seconds

Ответ 2

Я разрешаю эту проблему, изменяя "физический файл" 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>