NHibernate在使用Oracle 11g的TransactionScope出现问题

5
以下代码片段在 SQL Server 2008 (SP1) 上运行良好,但在 Oracle 11g 上调用 session.BeginTransaction() 时会抛出异常,错误信息为“Connection is already part of a local or a distributed transaction”(堆栈跟踪如下所示)。使用 “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 isolationLevel) 
           NHibernate.Transaction.AdoTransaction.Begin() 
           NHibernate.AdoNet.ConnectionManager.BeginTransaction() 
           NHibernate.Impl.SessionImpl.BeginTransaction() 
           MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(List`1& dataObjects) in S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs:line 3103
内部错误信息为:连接已经是本地或分布式事务的一部分 内部异常位于:Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel) Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel) System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction() NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)
4个回答

7
使用仅事务范围的问题在此处概述:NHibernate FlushMode Auto Not Flushing Before Find 看起来nhibernate(使用oracle方言和11g db w/opd.net v2.112.1.2的v3.1)需要自己的事务以避免刷新问题,但我无法让事务范围与nhibernate事务一起使用。
我好像无法让它工作:( 这可能是nhibernate或odp.net中的缺陷,不确定...
在此处发现相同的问题:NHibernate 3.0: TransactionScope and Auto-Flushing 已解决:找到了解决方案!通过将“enlist=dynamic;”放入我的oracle连接字符串中,问题得到了解决。我已经能够同时使用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 - enlisted into DTC transaction: Serializable 在连接上执行任何SQL之前。我将进行单元测试以确认正确执行。但是我不太确定Serializable是什么意思。

2
布拉德的答案使用了外部TransactionScope和内部NHibernate事务,enlist=dynamic,但似乎无法正常工作。好的,数据已经提交了。
但是,如果省略scope.Complete()或在tx.Commit()之后引发异常,则数据仍然会被提交(对于Oracle而言)。然而,由于某种原因,这对SQL-Server有效。
NHibernate事务负责自动刷新,但最终它们调用底层的ADO.NET事务。虽然许多来源鼓励上述模式作为解决auto-flush issue的NHibernate最佳实践,但是讨论本机ADO.NET的来源却说相反:不要将TransactionScope和内部事务一起使用,无论是对于Oracle还是SQL-Server。(请参见this questionmy answer
我的结论:不要将TransactionScope和NHibernate事务组合使用。如果要使用TransactionScope,请跳过NHibernate事务并手动处理刷新(另请参见NHibernate Flush doc)。

0
一个问题,为什么你要做内部session.BeginTransaction - 自从2.1 GA NHibernate将自动注册到TransactionScope上下文中,所以没有理由再自己做了。

0

来自NHibernate cookbook

请记住,与数据库交互时,NHibernate需要一个NHibernate事务。TransactionScope不能替代它。如下图所示,TransactionScope应完全包围会话和NHibernate事务。在会话被处理后,调用TransactionScope.Complete()。任何其他顺序很可能会导致像连接泄漏这样的严重问题,从而使生产崩溃。

我认为它也应该只使用TransactionScope就可以工作,但实际上不行,无论是在3.3.x.x还是4.0.0.400版本中都不行。

上述方法可能有效,但需要测试它是否适用于嵌套的TrancactionScope,内部TransactionScope定义了Transaction.Suppress(在使用SQL时),等等...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接