8

我承认,我并没有完全理解*Hibernate。

既然像Dapper这样的微型 ORM可以用来解决大多数数据访问需求,那么有哪些场景需要像 nHibernate 这样的大手笔呢?有哪些 nHibernate 大放异彩的例子?需要明确的是,我不认为“在不更改代码的情况下切换数据库的能力”有太多优势。在八年的编程生涯中,我实际上从来没有这样做过,而且这似乎是一个浪费时间的想法。

我愿意接受任何深思熟虑的回应,但这里有一些我有问题的例子:

  1. 与 Dapper 之类的东西相比,查询 API 什么时候值得您在映射中投入额外的工作?
  2. 您如何以一种限制开发工作并正常工作的方式利用延迟加载?
  3. 什么时候值得您花时间弄清楚如何批处理语句?
  4. 在什么情况下缓存系统比页面输出缓存更好?这只适用于非分布式环境吗?
  5. 像我这样的普通人怎么能理解 nHibernate 在分布式环境中的工作方式?考虑混合缓存、批处理和无状态会话,并考虑负载平衡的 Web 服务器将如何处理所有这些。
4

2 回答 2

8

哇,大问题。不知道一个凡人能回答这个问题。但我认为您太快忽略“切换数据库的能力”。有很多软件包,无论是商业的还是开源的,都提供了使用不同 RDBMS 作为后备存储的能力。管理用于部署到 2 个以上数据库平台的 SQL 绝对是一场噩梦,因此以可预测的方式构建 SQL(至少与手写相比)是一个巨大的优势。只是扮演魔鬼的拥护者,对于某些数据库平台,我可以看到事务吞吐量的增长使得数据库选择的成本也非常昂贵。大多数ORM'

我认为简短的回答是,当您的数据库对应用程序的需求达到一定程度的复杂性时,满足您的需求的成本就会低于 nhibernate 学习曲线所涉及的成本。我无法提供完整的答案,但会尝试就您的清单项目发表我的想法。

  1. 当你做的不仅仅是 CRUD。在多个数据库平台上进行复杂查询的需求可能就是一个很好的例子。在这种类型的应用程序上,您几乎可以最终维护两个独立的代码库(好吧,如果您使用存储的 proc 路线,它们真的会分离)并且将所有代码保存在 .net 中可能很有价值(能够统一例如,使用其余代码测试这些查询)。
  2. 除了在中等信任环境中看到的问题之外,我不确定延迟加载现在是否“不起作用”。在我看来,延迟加载的唯一问题是您需要注意它,以避免在获取大量数据时可能出现的一些问题,主要是 N+1 选择问题。
  3. 您不需要弄清楚如何批处理语句 - 您只需要设置一个配置值并忘记它。这是 NHibernate 以最小的努力为您所做的一个非常巨大的优化——当它只直接涉及操作和事务控制时,您的代码可以更简洁。
  4. 当您为不同的用户以不同的方式呈现页面或在域层中进行任何类型的非平凡处理时,缓存返回的数据可能会很有用。即使在基本场景中,通过页面输出缓存,您最终可能会在缓存中拥有编辑页面、详细信息页面等,而将数据缓存到更靠近源的位置,您只需要缓存一次实体。更靠近源的缓存还可以为您提供更多保护,防止提供过时的数据。面向数据的缓存也可以通过服务或通过将 nHibernate 指向进程外存储(如 memcached 或 redis)在多个应用程序之间共享。这在某些环境中可能非常有价值。
  5. 我不确定你需要了解它是如何工作的(很多时候我使用开源库来保护自己不需要了解这种事情的实现细节)。但简短的回答是,除了缓存(并且只有二级缓存)之外,在分布式场景中,这些行为都没有任何不同。只要您使用分布式缓存提供程序(或将所有服务器指向同一个进程外缓存提供程序),您在这方面也应该做得很好。

我只是在谈论 nHibernate,但我想 Hibernate 的故事大致相同。对于更大规模、更复杂的应用程序,可能会带来很多好处,但是为了获得这种好处,您需要承担很多额外的复杂性——它可能仍然没有为所有问题推出自己的解决方案复杂*Hibernate 为您解决。

你似乎也有很多关于缓存的问题。我建议阅读此链接以了解一级和二级缓存的工作原理。我不会在这里解释,因为听起来你的理解比我能适应这个已经很长的回复更深入:)

于 2012-08-02T00:02:34.633 回答
5

NHibernate 强大而强大,但您不必了解它的所有内容才能成功使用它。要回答您的问题:

  1. 我所知道的所有 .NET micro-ORMS 都没有任何 LINQ 支持,而是依赖于在代码中混合 SQL 字符串。使用 LINQ 构建查询可为您提供类型安全、编译时检查和出色的可重构性。如果所有查询都使用 SQL 字符串,请尝试重构包含数千个查询的代码库……哎呀!通过重构,我的意思是添加新列、新表等简单的事情,这在企业环境中一直在发生。重构字符串是可能的,这就是依赖存储过程的人们仍然需要做的事情,但如果我可以使用类型安全,我肯定不会选择这样做。

  2. 对于延迟加载,您唯一需要记住的是创建一个 SELECT N+1 场景。任何时候你有代码在域对象/实体上执行 foreach 循环,确保填充对象的查询使用了 .Fetch() 方法,该方法只是在 SQL 中创建一个 JOIN 并填充任何子对象。否则,当您遍历对象并点到任何子对象时,ORM 将不得不执行另一个 SELECT 语句来“获取”数据。基本上,在 NHibernate 术语中,Eager fetching 是您的朋友。

  3. 使用 NHibernate 进行批处理就像馅饼一样简单。在您的 NHibernate 配置中,打开批处理就可以了。之后,如果您确实需要,您可以在运行时为特定查询调整批处理大小。

  4. 我自己从来没有使用过二级缓存。我在大型企业环境中工作,我们的应用程序运行速度非常快,无需缓存。NHibernate 中的一级缓存虽然不需要配置,但可以简单地认为是更改跟踪。基本上,NHibernate 在内部保留了一个字典,其中包含它已经从数据库中检索到的对象以及哪些对象等待在数据库中保存/更新。一级缓存是我从来没有真正考虑过的,但我想在初级水平上了解它是如何工作的很好。

  5. 同样,我目前在企业环境中工作,我们有各种使用 NHibernate 的应用程序;一些非常基本,而另一些则使用 NHibernate 必须提供的所有强大功能。不过,根据我的经验,我通常看到的是,并非团队中的每个成员都需要成为 NHibernate 专家。通常 1 到 3 名开发人员知识渊博,其他所有人都不会担心,只需创建他们的实体、映射并继续他们的编程。一旦基础设施到位并且您的组织已经整理出它希望使用的模式,一切通常都是轻而易举的。

额外的想法:

NHibernate 真正闪耀的一个地方是它能够映射任何一种你扔给它的疯狂数据库设计。现在我并不是说在 90 年代初期将一些疯狂的数据库设计映射在一起很容易,您必须将存储过程和另一个表连接在一起,但这可能的。我一天中做过一些疯狂的映射。有些我什至认为是不可能的,因为数据库的设计目的并不是我们想要它做的事情,但是每次,通过持久性,我仍然设法利用 NHibernate 在映射好的和坏的数据库设计方面令人难以置信的灵活性来完成它。

使用 Micro-ORMS,您通常会在代码旁边嵌入大量 SQL 字符串。这如何被认为是清洁和高效的。似乎所有人现在都在将他们用来放入存储过程的东西放入他们的代码中。实际上,我确实在我的一些项目中使用了 Micro-ORM,尽管它是有意义的,但通常是当我只在一个表上查询一些简单的数据时——没有复杂的 WHERE 子句。

公平地说,我是那些投入大量时间学习 NHibernate 细节的人之一,但不是因为我需要工作,而是因为我只是想这样做。我和很多人一起工作,他们每天都在使用 NHibernate,但并没有完全理解它。但同样,他们不需要。你只需要知道一些基本的东西就可以了。

希望这可以帮助。

于 2012-08-03T08:44:48.893 回答