【问题标题】:Can I use NHibernate's AdoNetTransactionFactory with distributed transactions?我可以在分布式事务中使用 NHibernate 的 AdoNetTransactionFactory 吗?
【发布时间】:2012-01-24 19:34:18
【问题描述】:

我正在处理一个与 NHibernate 和 WCF 服务中的分布式事务相关的奇怪问题。详情请见Deadlocks causing 'Server failed to resume the transaction' with NHibernate and distributed transactions

似乎可以解决我的问题的一件事是使用 NHibernate 的 AdoNetTransactionFactory,而不是 AdoNetWithDistributedTransactionsFactory。

我相信 AdoNetWithDistributedTransactionsFactory 与使 NHibernate 的二级缓存机制正常工作有关,但我们没有使用它。将 AdoNetTransactionFactory 与分布式事务一起使用还存在哪些(如果有)其他问题?

感谢您的宝贵时间!

【问题讨论】:

    标签: nhibernate distributed-transactions


    【解决方案1】:

    我注意到您在其他问题/答案中提到:

    SqlConnection class is not thread-safe, and that includes closing the connection 
    on a separate thread. Based on this response we have filed a 
    bug report for NHibernate.
    

    但是,来自NHibernate's documentation

    11.2. Threads and connections
    

    您在创建 NHibernate Session 时应遵循以下做法:

  • 切勿为每个数据库连接创建多个并发 ISession 或 ITransaction 实例。

  • 在为每个数据库的每个事务创建多个 ISession 时要格外小心。 ISession 本身会跟踪对加载对象所做的更新,因此不同的 ISession 可能会看到陈旧的数据。

  • ISession 不是线程安全的!永远不要在两个并发线程中访问同一个 ISession。 ISession 通常只是一个单一的工作单元!

    如果您尝试使用 NHibernate 对连接进行多线程连接,那么它可能无法正常工作。您是否考虑过不同的 ORM,例如 Entity Framework

    无论你选择什么 ORM,数据库连接都不是线程安全的。这是普遍的。

    “许多数据库驱动程序不是线程安全的。使用单例意味着如果您有许多线程,它们将共享相同的连接。单例模式不会给您线程安全。它只是允许多个线程轻松共享一个“全球”实例。” - https://stackoverflow.com/a/6507820/1026459

  • 【讨论】:

    • Travis,我们遵循了所有 NH 多线程指南。问题出在 NH 本身 - 如果分布式事务被 DB 服务器中止,NH 将关闭另一个线程上的连接。
    【解决方案2】:

    AdoNetTransactionFactory分布式系统事务一起使用会导致这些事务被NHibernate忽略,其后果如下:

    • ConnectionReleaseMode.AfterTransaction 将不获尊重。相反,NHibernate 将在每个语句之后释放连接,因此将从池中重新获取下一个连接的连接。根据您的数据提供商,这可能会触发事务升级为分布式。
    • FlushMode.Commit 将不获尊重。将需要显式刷新。 (Auto 在查询可能仍然发生之前刷新。)
    • 需要与当前系统事务隔离的工作仍将包含在其中。 (除非连接字符串Enlist 属性是false。)此类工作可能包括id 生成器查询,例如检索表hilo 生成器的下一个高值。如果事务被回滚,NHibernate 可能会使用冲突的 id。
    • NHibernate 会话将无法正确跟踪它持有的实体锁。考虑到自己在事务之外,它会认为它对它们没有锁定。因此,它可能会尝试(例如根据用户代码请求)以低于数据库中事务已经持有的锁定级别重新锁定它们。不确定会导致什么结果。 (在最好的情况下,被忽略,在最坏的情况下......)
    • 一旦您开始修改数据,二级缓存将被禁用。在这种情况下,NHibernate 类型的“无效”缓存条目,并且仅在事务完成时重新启用它们,更新。但由于它不会意识到交易......
    • 某些扩展(可能是 Envers)可能依赖于 NHibernate 事务事件,并且不再按预期工作。

    【讨论】:

      【解决方案3】:

      我强烈建议升级到 nhibernate 3.2(或接近它的版本)。为什么?自 2.1 以来,AdoNetWithDistributedTransactionFactory 有了重大改进(读取重写)。事实上,它现在可以正确处理 TransactionScopes/ambient-transactions 等。当我们在生产环境中运行 2.1 时,我们遇到了许多与分布式事务相关的问题。我们几乎不得不自己修复大量的东西并重新编译 NHibernate。 3.2 似乎解决了这个主题的许多问题。

      我附近没有源,但如果内存没有让我失望,AdoNetTransactionFactory 不会检查/处理环境事务。因此,当会话中不存在一个事务时(通过 ISession.BeginTransaction()),您可以使用 NHibernate 启动事务。

      【讨论】:

      • 感谢您的回复。我假设您阅读了我提到我们正在使用 NH2.1 的另一个问题。实际上,我们确实尝试升级到 3.2,但它并没有解决我们的问题。
      • 在我们的测试中,我们发现 AdoNetTransactionFactory 不知道环境事务,但底层的 SqlConnection 仍然参与其中,所以即使我们不使用 NH 事务,一切仍然有效。我相信 AdoNetWithDistributedTransactionsFactory 主要参与确保 NH 的二级缓存机制正常工作,但我想知道它是否还有其他问题。
      • AdoNetWithDistributedTransactionFactory 将在更多情况下自动加入环境事务,并且有时会在不使用 NHibernate 事务的情况下工作。尽管不幸的是,即使在 3.3 中也存在一些问题,所以仍然建议除了 TransactionScope 之外始终使用 NHibernate 事务。由于 System.Transactions 和 System.Data 的限制,我担心当前方法可能存在一些本质上无法修复的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-17
      • 1970-01-01
      相关资源
      最近更新 更多