Проблема NHibernate TransactionScope с Oracle 11g
Следующий фрагмент кода отлично работает с SQL Server 2008 (SP1), но с Oracle 11g при вызове session.BeginTransaction() выдает исключение с сообщением "Соединение уже является частью локальной или распределенной транзакции" (трассировка стека показана ниже), Использование "NHibernate.Driver.OracleDataClientDriver".
Кто-нибудь еще сталкивался с этим?
using (var scope = new TransactionScope())
{
using (var session = sessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
// do what you need to do with the session
transaction.Commit();
}
scope.Complete();
}
Исключение в: в NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel изоляция Level) в NHibernate.Transaction.AdoTransaction.Begin() в NHibernate.AdoNet.ConnectionManager.BeginTransaction() в NHibernate.Impl.SessionImpl.BeginTransaction() в MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(List`1& dataObjects) в S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs: строка 3103 Внутреннее сообщение об ошибке было: Соединение уже является частью локальной или распределенной транзакции Внутреннее исключение по адресу: в Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel изоляция Level) в Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel изоляция Level) в System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction() в NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel изоляция Level)
4 ответа
Проблема с использованием только области транзакции описана здесь: NHibernate FlushMode Auto не очищается перед поиском
Похоже, что nhibernate (v3.1 с оракул диалект и 11g дБ w/opd.net v2.112.1.2) требует своих собственных транзакций, чтобы избежать проблемы сброса, но я не смог получить объем транзакции для работы с nhibernate сделки.
Я не могу заставить его работать:(это может быть дефект в nhibernate или odp.net, не уверен...
обнаружил ту же проблему здесь: NHibernate 3.0: TransactionScope и Auto-Flushing
ИСПРАВЛЕНО: найдено решение! поставив "enlist=dynamic;" в мою строку соединения оракула проблема была решена. Мне удалось использовать как транзакцию nhibernate (чтобы исправить проблему сброса), так и объем транзакции, например, так:
ISessionFactory sessionFactory = CreateSessionFactory();
using (TransactionScope ts = new TransactionScope())
{
using (ISession session = sessionFactory.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
//do stuff here
tx.Commit();
}
ts.Complete();
}
Я проверил свои файлы журналов и нашел это: 2011-06-27 14:03:59,852 [10] DEBUG NHibernate.Impl.AbstractSessionImpl - зачислен в транзакцию DTC: Сериализуемый
до того, как какой-либо SQL был выполнен в соединении. Я проведу модульное тестирование, чтобы подтвердить правильность выполнения. Я не слишком уверен, что сериализуемый говорит мне, хотя
Ответ Брэда с использованием внешнего TransactionScope и внутренней транзакции NHibernate с enlist=dynamic, похоже, не работает должным образом. Хорошо, данные передаются.
Но если вы опустите scope.Complete() или создадите исключение после tx.Commit(), данные все равно будут зафиксированы (для Oracle)! Однако по какой-то причине это работает для SQL-Server.
Транзакции NHibernate заботятся об автоматической очистке, но в конце они вызывают основную транзакцию ADO.NET. В то время как многие источники рекомендуют использовать вышеупомянутый шаблон в качестве наилучшей практики для решения проблемы автоматического сброса NHibernate, источники, обсуждающие нативный ADO.NET, говорят об обратном: НЕ используйте TransactionScope и внутренние транзакции вместе, не для Oracle и не для SQL-Server. (См. Этот вопрос и мой ответ)
Мой вывод: не объединяйте транзакции TransactionScope и NHibernate. Чтобы использовать TransactionScope, пропустите транзакции NHibernate и обработайте сброс вручную (см. Также документ NHibernate Flush).
Из поваренной книги NHibernate
Помните, что NHibernate требует транзакции NHibernate при взаимодействии с базой данных. TransactionScope не является заменой. Как показано на следующем рисунке, TransactionScope должен полностью окружать сеанс и транзакцию NHibernate. Вызов TransactionScope.Complete() должен произойти после завершения сеанса. Любой другой заказ, скорее всего, приведет к неприятным сбоям в работе, таким как утечки соединения.
Мое мнение также заключается в том, что он должен работать вместе с TransactionScope, но это не так, ни в 3.3.xx, ни в версии 4.0.0.400.
Приведенный выше рецепт может работать, но нужно проверить его с помощью вложенного TrancactionScope, с внутренним TransactionScope, для которого определен Transaction.Suppress (при использовании SQL) и т. Д.
Один вопрос, почему вы выполняете внутреннюю сессию.BeginTransaction - начиная с версии 2.1 GA NHibernate автоматически регистрируется в контекстах TransactionScope, поэтому больше нет причин делать свою собственную.