2010-09-22 164 views
5

以下代码片段适用于SQL Server 2008(SP1),但使用Oracle 11g对session.BeginTransaction()的调用会引发异常,并显示消息'Connection is already part of a local or a part of a local or a分布式事务“(堆栈跟踪如下所示)。使用'“NHibernate.Driver.OracleDataClientDriver”“。Oracle 11g的NHibernate TransactionScope问题

有没有其他人遇到过这个问题?

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) 

回答

0

一个问题,你为什么要这么做内session.BeginTransaction - 自2.1 GA的NHibernate会自动注册到TransactionScope的背景​​,所以没有理由这样做你自己的了。

+3

这可能是让NHibernate的自动冲洗正常工作 – Konstantin 2012-04-20 08:13:27

7

只使用事务范围的问题是这里概述: NHibernate FlushMode Auto Not Flushing Before Find

看来NHibernate的(V3.1与Oracle方言和11g数据库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:59852 [10] DEBUG NHibernate.Impl.AbstractSessionImpl - 登记到DTC事务:序列化

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

2

Brads答案,使用外部TransactionScope和内部NHibernate事务enlist =动态,似乎不能正常工作。好的,数据被提交。

但是,如果您在tx.Commit()之后省略scope.Complete()或引发异常,那么数据仍然会被提交(对于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)。

0

从NHibernate的食谱

记住NHibernate的与数据库进行交互时需要NHibernate的交易。 TransactionScope不是替代品。如下图所示,TransactionScope应完全包围会话和NHibernate事务。 对SessionScope.Complete()的调用应该在会话被处置后进行。任何其他命令都可能导致令人讨厌的生产崩溃,如连接泄漏。

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

上述食谱可以工作,但需要嵌套TrancactionScope进行测试,与已定义了Transaction.Suppress内的TransactionScope(使用SQL时),等等