мы написали клиент C # 3.5, который общается с базой данных Oracle (11g), используя ODP.NET.
В этом приложении есть пакетный процесс, в котором выполняется длительная задача, выполняющая различные вызовы базы данныхa TransactionScope.
В нашей среде разработки все идет хорошо, но в среде UAT одного из наших клиентов (у которого много данных) возникают две чередующиеся (иногда одна, иногда другая ...) ошибки:
- Невозможно подключиться к распределенной транзакции
- Транзакция прервана.(внутреннее исключение: тайм-аут транзакции)
В настоящее время мы используем тайм-аут один день для транзакции (в целях тестирования).
Запуск указанного процессав среде UAT вызывает остановку после прибл.10 минут с одним из вышеперечисленных исключений, поэтому не приближайтесь к значению тайм-аута.
Вот фрагмент трассировки стека для второй ошибки:
at System.Transactions.TransactionStatePromotedAborted.CreateAbortingClone(InternalTransaction tx)
at System.Transactions.DependentTransaction..ctor(IsolationLevel isoLevel, InternalTransaction internalTransaction, Boolean blocking)
at System.Transactions.Transaction.DependentClone(DependentCloneOption cloneOption)
at System.Transactions.TransactionScope.SetCurrent(Transaction newCurrent)
at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope..ctor(TransactionScopeOption scopeOption)
at System.Transactions.TransactionScope..ctor()
at Application.Domain.DataAccess.Oracle.EntityDaoBase`2.SaveItem(TEntity item, EntityReference`1 user)
Процесс пытается сохранить элемент вБД в рамках транзакции, но трассировка стека показывает, что конструктор вызван для класса TransactionScope, то есть он создает новый TransactionScope.
Прав ли я до сих пор?
Потому что я неОн не очень хорошо знает внутреннюю работу TransactionScope, но, похоже, когда вы вызываете метод в области действия, он создаст новую транзакцию (предположительно наследуя от внешней транзакции).
Может быть, еслиЯ прав, что эта новая транзакция не наследует правильный тайм-аут (но по умолчанию), так что вложенная транзакция вызовет это исключение тайм-аута?
Если нет, какие-либо мысли о том, что это может быть?Примечательно, что в методах, вызываемых из внешней транзакции, не определены вложенные транзакции.
Любая помощь будет принята с благодарностью!
Редактировать 1:
Упрощенный фрагмент кода функции:
public void SomeLengthyBatchProcess()
{
using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(1, 0, 0, 0)))
{
foreach (var item in Items)
{
SaveItemToDB(item);
}
transaction.Complete();
}
}
public void SaveItemToDB(object item)
{
using (var transaction = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(1, 0, 0, 0)))
{
// Performing data persistency here
transaction.Complete();
}
}
Редактировать 2:
Ладно, как оказалось, там есть вложенная транзакция, происходящая в методе SaveItemToDB.Немного покопавшись в коде, созданном коллегой, я увидел, что у него определен собственный TransactionScope, но без параметров и времени ожидания.
После изменения этого метода, чтобы он имел те же параметры, что и время ожидания, я запустил кодснова на сервере клиента и все равно не повезло (снова транзакция прервала ошибку с тайм-аутом).
Итак, мои вопросы теперь следующие:
- Нужно ли определять тайм-аутзначения для вложенных транзакций, или они наследуют это от внешней транзакции?
- Как возможно, что может возникнуть исключение тайм-аута, когда настройка тайм-аута (предположительно, помимо внутренней работы, о которой я не знаю)То же самое для всех областей транзакции и имеет значение тайм-аута, определенное в 1 день, где исключение происходит после прибл.10 минут?
- Можно ли предотвратить создание Oracle распределенной транзакции для транзакций с одинаковой строкой соединения?
- Может ли быть, что дополнительные издержки распределенной транзакции вызовут исключения, подобныеодна транзакция прервана?
Я обновил фрагмент кода, чтобы он лучше отражал ситуацию.
(кстати: вторая, вложенная транзакция необходима, поскольку DAL также отдельносохраняются некоторые дочерние элементы, если они есть, и, конечно, весь элемент должен быть откатан, если что-то пойдет не так, при сохранении дочерних элементов)
Надеюсь, с этим дополнением будет легче пролить светпо этому вопросу!