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