Oracle 11g的NHibernate TransactionScope问题

时间:2010-09-22 00:37:20

标签: oracle nhibernate transactionscope

以下代码片段适用于SQL Server 2008(SP1),但对于Oracle 11g,对session.BeginTransaction()的调用会抛出异常,并显示消息“Connection已经是本地或分布式事务的一部分”(堆栈跟踪)如下所示)。使用'“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();
}
     Exception at:    at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)
           at NHibernate.Transaction.AdoTransaction.Begin()
           at NHibernate.AdoNet.ConnectionManager.BeginTransaction()
           at NHibernate.Impl.SessionImpl.BeginTransaction()
           at MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(List`1& dataObjects) in S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs:line 3103

        Inner error message was: Connection is already part of a local or a distributed transaction
        Inner exception at:    at Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel isolationLevel)
           at Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(IsolationLevel isolationLevel)
           at System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction()
           at NHibernate.Transaction.AdoTransaction.Begin(IsolationLevel isolationLevel)

4 个答案:

答案 0 :(得分:7)

此处概述了仅使用事务范围的问题: NHibernate FlushMode Auto Not Flushing Before Find

看起来nhibernate(v3.1与oracle方言和11g db w / opd.net v2.112.1.2)需要它自己的事务来避免刷新问题,但我无法让事务范围工作与nhibernate交易。

我似乎无法让它工作:( 这可能是nhibernate或odp.net中的缺陷,不确定......

在这里发现了同样的问题: NHibernate 3.0: TransactionScope and Auto-Flushing

FIXED:找到了解决方案!通过输入“enlist = dynamic;”进入我的oracle连接字符串,问题得到了解决。我已经能够同时使用nhibernate事务(修复flush问题)和事务范围:

        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事务:Serializable

在连接上执行任何SQL之前。我将进行单元测试以确认正确执行。我不太确定序列化可以告诉我什么

答案 1 :(得分:2)

Brads回答,使用外部TransactionScope和内部NHibernate事务与enlist = dynamic,似乎无法正常工作。好的,数据得到了提交。

但是如果省略scope.Complete()或在tx.Commit()之后引发异常,数据仍然会被提交(对于Oracle)!但是,出于某种原因,这适用于SQL-Server。

NHibernate事务处理自动刷新,但最终它们调用底层的ADO.NET事务。虽然许多消息来源鼓励将上述模式作为NHibernate解决auto-flush issue的最佳实践,但讨论本地ADO.NET的消息来源则相反:不要将TransactionScope和内部事务一起使用,不要用于Oracle而不用于SQL-Server。 (请参阅this questionmy answer

我的结论:不要将TransactionScope和NHibernate事务组合在一起。要使用TransactionScope,请跳过NHibernate事务并手动处理刷新(另请参阅NHibernate Flush doc)。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

来自NHibernate食谱

请记住,NHibernate在与数据库交互时需要NHibernate事务。 TransactionScope不是替代品。如下图所示,TransactionScope应完全包围会话和NHibernate事务。 对TransactionScope.Complete()的调用应该在会话处理完毕后发生。任何其他顺序很可能会导致令人讨厌的生产崩溃错误,如连接泄漏。

我的意见是它应该与TransactionScope一起使用,但它不会在3.3.x.x中也不适用于4.0.0.400版本。

上面的配方可能有效,但需要使用嵌套的TrancactionScope进行测试,内部TransactionScope定义了Transaction.Suppress(使用SQL时),等等......