Nhibernate 出现 TransactionScope 错误 - DTC 事务准备阶段失败 - 升级到 Nhibernate 3.0
在事务 Scope.Eg 中使用 Nhibernate 和 ADO.Net 操作时,出现以下异常。 Nhibernate 2.1 没问题,但现在升级到 3.0 会抛出错误。
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
GetmemberId(); --> NHibernate Call
Update(); ADO Call OracleDB
}
由于这充当环境事务,Nhibernate 会尝试在外部事务完成之前立即处理该事务。如果我错了,请纠正我,是否有任何解决方案,因为可以帮助我,但是当我将 Nhibernate 调用移到 TransactionScope 之外时,一切正常。我给出的示例是示例一,我的示例涉及更复杂的示例,因为我将两个调用都保留在 TransactionScope 内,并且我得到的错误如下,
错误 13 NHibernate.Impl.AbstractSessionImpl - DTC 事务预准备 阶段失败 System.ObjectDisposeException:无法访问已处置的对象 目的。对象名称:“交易”。在 System.Transactions.Transaction.DependentClone(DependentCloneOption 克隆选项)在 System.Transactions.TransactionScope.SetCurrent(事务 newCurrent) 在 System.Transactions.TransactionScope.PushScope()
在 System.Transactions.TransactionScope.Initialize(事务 transactionToUse、TimeSpan 范围超时、布尔互操作模式指定) 在 System.Transactions.TransactionScope..ctor(事务 交易使用)在 NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment 准备入伍)2011-02-08 13:41:46,033 错误 13 NHibernate.Impl.AbstractSessionImpl - DTC 事务预准备阶段 失败的 System.ObjectDisposeException:无法访问已处置的对象 目的。对象名称:“交易”。在 System.Transactions.Transaction.DependentClone(DependentCloneOption 克隆选项)在 System.Transactions.TransactionScope.SetCurrent(事务 newCurrent) 在 System.Transactions.TransactionScope.PushScope()
在 System.Transactions.TransactionScope.Initialize(事务 transactionToUse、TimeSpan 范围超时、布尔互操作模式指定) 在 System.Transactions.TransactionScope..ctor(事务 交易使用)在 NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment 准备入伍)
I am getting the following exception when using Nhibernate and ADO.Net operations inside the transaction Scope.Eg. It was fine with Nhibernate 2.1 but now upgraded to 3.0 which throws error.
using (var scope = new TransactionScope(TransactionScopeOption.Required))
{
GetmemberId(); --> NHibernate Call
Update(); ADO Call OracleDB
}
Since this acts as ambient transaction, Nhibernate tries to dispose the transaction soon before the outer transaction completes.correct me if I am wrong, Is there any solution because help me , But When I move the Nhibernate call outside TransactionScope everything works fine. The example I have given is sample one, mines involves a more complex one, since I have keep both the calls inside TransactionScope and the error Iam getting is as following,
ERROR 13 NHibernate.Impl.AbstractSessionImpl - DTC transaction prepre
phase failed System.ObjectDisposedException: Cannot access a disposed
object. Object name: 'Transaction'. at
System.Transactions.Transaction.DependentClone(DependentCloneOption
cloneOption) at
System.Transactions.TransactionScope.SetCurrent(Transaction
newCurrent) at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction
transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified)
at System.Transactions.TransactionScope..ctor(Transaction
transactionToUse) at
NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment
preparingEnlistment) 2011-02-08 13:41:46,033 ERROR 13
NHibernate.Impl.AbstractSessionImpl - DTC transaction prepre phase
failed System.ObjectDisposedException: Cannot access a disposed
object. Object name: 'Transaction'. at
System.Transactions.Transaction.DependentClone(DependentCloneOption
cloneOption) at
System.Transactions.TransactionScope.SetCurrent(Transaction
newCurrent) at System.Transactions.TransactionScope.PushScope()
at System.Transactions.TransactionScope.Initialize(Transaction
transactionToUse, TimeSpan scopeTimeout, Boolean interopModeSpecified)
at System.Transactions.TransactionScope..ctor(Transaction
transactionToUse) at
NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Prepare(PreparingEnlistment
preparingEnlistment)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
尝试
Configuration.SetProperty(Environment.TransactionStrategy,"NHibernate.Transaction.AdoNetTransactionFactory")
或者在 nhibernate config 中
它对我有用 =)
Try
Configuration.SetProperty(Environment.TransactionStrategy,"NHibernate.Transaction.AdoNetTransactionFactory")
Or in nhibernate config
It worked for me =)
我们遇到了同样的错误,这是由我们在 NHibernate 的 Web Api 中使用会话和事务的方式引起的。
我们应该使用每个请求会话。 (这可以是 Web 请求或 NServiceBus 处理程序的执行。)当请求开始时,您应该打开一个会话并启动一个事务。
我们没有那样做。在我们的存储库中,我们为每个数据库请求创建了一个新的会话和事务。这意味着我们对一个请求不是只有一个会话/事务,而是很多。
对我们来说,该错误的根本原因是我们在一个会话中加载一个实体(域模型对象),修改它,然后使用不同的会话保存它。当 NHibernate 执行更新调用时,加载会话/事务已经被提交、刷新和关闭。
解决方案是将我们的会话/事务创建从存储库中提取到控制器层(可以使用 HttpModule 进行 REST 调用和/或使用依赖注入进行面向方面的编程)。然后,这一会话/事务在 REST 调用或 NServiceBus 处理程序执行的生命周期内有效,并用于该调用期间的所有数据库访问。当该调用结束时,它将根据需要提交或回滚。
上面给出的设置配置属性的答案只是关闭 DTC 并恢复到执行 NHibernate 事务的旧方法。如果您不需要将 Web Api 扩展到多个实例,这可能会解决您的问题,但如果您这样做,这会给您带来问题。
We ran into this same error, and it was caused by the way we used sessions and transactions in our Web Api with NHibernate.
We should have been using session-per-request. (This can be a web request or the execution of a NServiceBus handler.) When a request starts, you should open a session and start a transaction.
We were not doing that. In our repositories, we created a new session and transaction for every database request. This meant that rather than having a single session/transaction for a request, we had many.
The root cause of the bug for us was that we were loading an entity (domain model object) in one session, modifying it, and saving it using a different session. By the time NHibernate executed the update call, the loading session/transaction had already been committed, flushed, and closed.
Solution was to pull our session/transaction creation out of the repositories and up to the Controller layer (doable using a HttpModule for REST calls and/or with aspect oriented programming using dependency injection). This one session/transaction then lives for the lifetime of the REST call or NServiceBus handler execution and is used for all database access during that call. When that call ends, it will be committed or rolled back as appropriate.
The answer given above setting the config property simply turns off DTC and reverts to the older way of doing NHibernate transactions. That may solve the problem for you if you never have to scale up your Web Api to multiple instances, but if you do, this will cause you problems.