以下代码片段适用于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)
答案 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 question和my 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时),等等......