与Oracle 11g的NHibernate事务处理范围问题

与Oracle 11g的NHibernate事务处理范围问题,oracle,nhibernate,transactionscope,Oracle,Nhibernate,Transactionscope,下面的代码片段适用于SQL Server 2008(SP1),但在Oracle 11g中,对session.BeginTransaction()的调用引发异常,消息为“连接已经是本地或分布式事务的一部分”(堆栈跟踪如下所示)。使用“NHibernate.Driver.OracleDataClientDriver” 还有其他人碰到过这个吗 using (var scope = new TransactionScope()) { using (var session = sessionFact

下面的代码片段适用于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 IsolationLevel) 在NHibernate.Transaction.AdoTransaction.Begin()处 在NHibernate.AdoNet.ConnectionManager.BeginTransaction()上 在NHibernate.Impl.SessionImpl.BeginTransaction()上 在S:\MetraTech\BusinessEntity\DataAccess\Persistence\StandardRepository.cs:第3103行中的MetraTech.BusinessEntity.DataAccess.Persistence.StandardRepository.SaveInstances(列出'1和dataObjects)处 内部错误消息为:连接已经是本地或分布式事务的一部分 位于的内部异常:位于Oracle.DataAccess.Client.OracleConnection.BeginTransaction(IsolationLevel IsolationLevel) 位于Oracle.DataAccess.Client.OracleConnection.BeginDbTransaction(隔离级别隔离级别) 位于System.Data.Common.DbConnection.System.Data.IDbConnection.BeginTransaction()处 在NHibernate.Transaction.AdoTransaction.Begin处(IsolationLevel IsolationLevel)
有一个问题,为什么要进行内部会话。BeginTransaction-由于2.1 GA NHibernate将自动注册到TransactionScope上下文中,因此没有理由再进行自己的操作。

此处概述了仅使用事务作用域的问题:

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

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

在此处发现相同的问题:

修复:找到了一个解决方案!通过将“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:59852[10]调试NHibernate.Impl.AbstractSessionImpl-登记到DTC事务中:可序列化


在连接上执行任何SQL之前。我将进行单元测试以确认正确执行。我不太确定serializable告诉我的是什么,尽管Brads回答,使用外部TransactionScope和内部NHibernate事务(enlist=dynamic)时,似乎工作不正常。好的,数据已提交

但是,如果省略了scope.Complete()或在tx.Commit()之后引发异常,数据仍然会被提交(对于Oracle)!但是,由于某些原因,这对SQL Server有效

NHibernate事务负责自动刷新,但最终它们调用底层ADO.NET事务。虽然许多资料来源鼓励将上述模式作为NHibernate解决问题的最佳实践,但讨论本机ADO.NET的资料来源说的恰恰相反:不要将TransactionScope和内部事务一起使用,不要用于Oracle,也不要用于SQL-服务器。(请参阅和)


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

来自NHibernate cookbook

记住,NHibernate在与数据库交互时需要NHibernate事务。TransactionScope不是替代品。如下图所示,TransactionScope应该完全围绕会话和NHibernate事务。对TransactionScope.Complete()的调用应在会话处理后发生。任何其他订单都极有可能导致严重的生产崩溃错误,如连接泄漏

我的意见是,它应该与TransactionScope一起工作,但在3.3.x.x和4.0.0.400版本中都不能

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

        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();
        }