与Oracle 11g的NHibernate事务处理范围问题
下面的代码片段适用于SQL Server 2008(SP1),但在Oracle 11g中,对session.BeginTransaction()的调用引发异常,消息为“连接已经是本地或分布式事务的一部分”(堆栈跟踪如下所示)。使用“NHibernate.Driver.OracleDataClientDriver” 还有其他人碰到过这个吗与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
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();
}