【问题标题】:NHibernate 3.0: TransactionScope and Auto-FlushingNHibernate 3.0:TransactionScope 和自动刷新
【发布时间】:2011-07-08 10:54:54
【问题描述】:

在 NHibernate 3.0 中,FlushMode.Auto 仅在环境事务下运行(即不启动 NHibernate 事务)时不起作用。应该吗?

using (TransactionScope scope = new TransactionScope()) 
{
    ISession session = sessionFactory.OpenSession();
    MappedEntity entity = new MappedEntity() { Name = "Entity", Value = 20 };
    session.Save(entity);

    entity.Value = 30;
    session.SaveOrUpdate(entity);

    // This returns one entity, when it should return none
    var list = session.
               CreateQuery("from MappedEntity where Value = 20").
               List<MappedEntity>();
}

(无耻盗取this related question的例子)

在 NHibernate 源代码中,我可以看到它正在检查是否有正在进行的事务(在 SessionImpl.AutoFlushIfRequired 中),但相关方法(SessionImpl.TransactionInProgress)不考虑环境事务 - 不像它的表亲 ConnectionManager.IsInActiveTransaction,它 确实考虑环境事务。

【问题讨论】:

  • 感谢上面的详细分析,我已将其添加到工单中,修复应在 NH 4.1.x.x 中。
  • 以上代码:有时你无法避免保存然后从同一个事务中读取。 但在您的情况下(在大多数情况下),无需在该事务中进行读取。 另一种可能性是在读取之前执行 session.Flush()。我知道这是 NHibernate 应该做的事情,但是......

标签: nhibernate transactionscope flush distributed-transactions nhibernate-3


【解决方案1】:

好消息。感谢 Jeff Sternal(他很好地发现了问题)我更新了 https://nhibernate.jira.com/browse/NH-3583 并感谢 NH 工作人员,已经有修复和拉取请求所以在即将发布的 4.1.xx 版本将修复此问题。

【讨论】:

  • 最新版本的 NH 已在 NuGet 上,因此此问题现已修复。
【解决方案2】:

您应该始终使用显式 NHibernate 事务。

using (TransactionScope scope = new TransactionScope()) 
using (ISession session = sessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
    //Do work here
    transaction.Commit();
    scope.Complete();
}

我看到你也在 NH 开发者列表中写道 - 虽然这在未来可能会改变,但现在就是这样。

【讨论】:

  • 没有争论该指南的优点(Ayende 曾多次提出异议),它没有回答我的问题,这与代码当前的工作方式无关。这真的是关于理想行为:是否只需要在环境事务下自动刷新?相反,NHibernate(或者实际上,任何其他 ORM)是否有任何理由在环境事务下自动刷新?
  • 我认为 Ayende 在他的一些帖子中也提到了环境事务是有效的。因此,如果您使用环境事务并嵌套它们,上面的代码将导致错误,就像 @brad 使用 oracle 描述的那样。无论如何,伙计们已经修复了这个错误,当 NH 4.1.x.x 推出时,一切都会正常......
【解决方案3】:

Diego 提供的答案不适用于您拥有 oracle 数据库的情况。 (releated question)。 session.BeginTransaction 将失败,因为连接已经是事务的一部分。

看起来我们必须在我们的应用程序(WCF、NHibernate、Oracle)中围绕这个问题编写一些代码,但这感觉就像 NHibernate 应该提供开箱即用的东西。 因此,如果有人有好的答案,将不胜感激。

【讨论】:

    【解决方案4】:

    对我来说,我不知道背后的原因,但在会话被处理之前强制会话刷新似乎对我有用。例如 使用(会话) { //做你的工作

    session.Flush(); }

    我验证了这适用于我的分布式事务,因为如果不这样做,当 TransactionScope 被释放时,我总是得到“事务已中止”。

    即使将 session.FlushMode 设置为 Commit 也不适合我。

    【讨论】:

    • 是的,对于分布式事务,即使提交时自动刷新也会失败。我认为线程也存在一些问题。 NServicebus里面有一段代码是用的:Thread.Sleep(10) :D There'
    猜你喜欢
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多