使用 NHibernate 从头开始​​:新的大型应用程序的提示

Posted

技术标签:

【中文标题】使用 NHibernate 从头开始​​:新的大型应用程序的提示【英文标题】:Starting from scratch with NHibernate: tips for a new, large, application 【发布时间】:2010-09-14 18:18:55 【问题描述】:

我正在编写一个用于重写现有应用程序的框架。我们有一个包含大约 900 个表的数据模型,总共有 11000 个字段,并且该字段中的数据库接近 120 GB。我的新实现的基本元素是 WPF、NHibernate 3、C#、.NET 4.0、NHibernate.Validator 和 Spring。该应用程序本身是数据/事务密集型的,我们最大的安装有大约 300 个并发用户。

我想要反馈的几点是:

Spring 是一个不错的选择吗?为什么我要选择不同的(城堡?)。我确实有启动时间的问题,但我已经能够把它恢复到 14 秒。不过,我并没有注意到 Spring 和 Castle 之间有太大的区别。更短的启动时间当然是受欢迎的;

我正在使用身份字段,但请理解这不是最佳选择。有什么可行的替代方案;

数据显示通过短会话完成,每个查询一个。另一方面,数据输入在工作流的整个持续时间内都有一个会话/事务,最多可能需要 10-20 分钟(更常见的是 2-4 分钟)。在整个持续时间内是否有会话/事务的替代方案?我该如何设置?

我对所有的意见都持开放态度,并希望整合那些工作时间更长、比我拥有更多 NHibernate 经验的人的想法。

(顺便说一句:我知道我有点不知所措,但这是我更喜欢的方式。)

编辑:我对 HiLo 过于苛刻,但经过一些研究,Guid 似乎更适合我的情况。

【问题讨论】:

我已经阅读了更多关于这方面的内容并进行了研究,例如NHibernate 中的实现,我必须说它看起来确实很有趣。我想我误解了早期的文档。我会考虑这个的。 我决定选择 Guid。这个选择是因为我需要支持复制,我喜欢在所有实体上拥有唯一 ID 的想法,因为这会让我的值太少而无法放入所有 ID。我们的大型安装已经接近 20 亿个唯一实体。旧系统没有所有实体的代理 ID,因此无论如何这都会给这个新系统带来问题。 【参考方案1】:

Hilo 是分配标识符的最快方法。使用身份字段有效,并且更安全(见下文),但由于标识符是由数据库生成的,因此每次插入行都需要读取操作来确定行的标识符。

如果您要使用 hilo,请确保您了解算法工作原理的详细信息。 (我认为它在本网站的其他地方进行了描述。)如果您对列或 hilo 的数据类型或“lo”值做出错误的选择,您最终可能会出现回绕,这将导致生成已使用的数字,这当然是非常糟糕的。

处理数据输入的典型方法是关闭会话,执行数据输入,然后将更新的对象附加到新会话。文档中对此进行了介绍。

附加的棘手之处在于:假设对象 A 包含对对象 B 的引用,而对象 B 包含对对象 C 的引用。如果您在初始会话期间“触摸”了对象 A 和 B,A 和 B 将已经加载,B 会包含对 C 的代理引用。如果你将 A 附加到新会话,但忘记附加 B,B 的代理引用仍会指向旧的已关闭会话,如果你尝试这将导致异常跟随它。

要做到这一点可能比看起来要难。在初始会话期间,如果您调用了一个函数,该函数在对象图中进行了某种搜索,那么以后可能很难确切知道哪些对象需要附加到新会话才能使一切正常运行。

根据与数据库的连接的可靠性,保持会话打开以进行数据输入操作并避免将对象附加到新会话所涉及的潜在问题可能是更好的选择。这在很大程度上取决于您的对象模型有多复杂以及您需要对这些对象做什么。

您使用的数据库也很重要。例如,Postgres 使用 MVCC,因此打开的会话永远不会阻止其他用户从数据库中读取。在使用行锁定的数据库中,锁定是长会话问题的很大一部分。

【讨论】:

我在 HiLo 上阅读了更多内容,Guids 似乎是一个更好的选择。虽然具有相同的优点。关于会话:数据完整性对我们来说非常重要,所以我主要担心是否要为整个业务事务保持事务打开。从长远来看,很难确定任一选项的影响。 长事务的主要问题是您最终会在数据库中锁定很长时间的行。这可以强制其他数据库操作等到你完成(取决于隔离级别),并且如果数据库检测到死锁,它将任意选择一个事务回滚以打破死锁。 另一件值得一提的事情是,如果尝试将对象写入数据库失败,并且您想再试一次,则应该使用新对象重新开始。 (因为对象可能由于写入尝试失败而更新了一半。)如果对象以前从未在数据库中,处理此问题的最简单方法是定义一个复制构造函数,该构造函数复制除标识符之外的所有内容,并克隆所有的对象。您的复制构造函数不会克隆对象的代理层,这是“搞砸”的部分。

以上是关于使用 NHibernate 从头开始​​:新的大型应用程序的提示的主要内容,如果未能解决你的问题,请参考以下文章

从头基于空镜像scratch创建一个新的Docker镜像

Nhibernate 3.2 开始到完成使用内置 conForm 的演练

实体框架与 NHibernate - 性能

ORM篇——使用NHibernate配置对象实体的一些小问题

将新的“子”列表分配给“父”时 NHibernate 孤儿

遗留数据库上的 NHibernate