2

我正在使用一个中等大小的 SQL Server 2008 数据库(大约 120 个表,备份压缩大约 4GB),其中所有表主键都声明为简单的 int 列。

目前,NHibernate 使用增量标识生成器生成主键值,该生成器迄今为止运行良好,但无法迁移到多处理环境。

系统上的负载正在增长,因此我正在评估允许使用多个服务器访问公共数据库后端所需的工作。

过渡到hi-lo生成器似乎是最好的方法,但我找不到很多关于这种迁移如何工作的细节。

NHibernate 会自动为我在 hi-lo 表中创建行,还是我需要手动编写这些脚本?

如果 NHibernate 确实自动插入行,它是否正确考虑了现有的键值?

如果 NHibernate 确实自动处理事情,那就太好了。如果没有,是否有任何工具可以提供帮助?

更新

NHibernate 的增量标识符生成器完全在内存中工作。它是通过从表中选择已用标识符的最大值来播种的,但从那时起,它会通过简单的增量分配新值,而不参考底层数据库表。如果任何其他进程向表中添加行,则最终会导致主键冲突。你可以在一个进程中运行多个线程就好了,但你不能运行多个进程。

相比之下,NHibernate身份生成器通过使用身份列配置数据库表来工作,将主键生成的控制权交给数据库。这很好用,但会损害工作单元模式。

hi-lo算法介于两者之间——主键的生成通过数据库进行协调,允许多处理,但实际分配可以完全在内存中进行,避免了工作单元模式的问题。

4

3 回答 3

2

要使用 hi-lo 生成器,您需要创建查找表,该表将存储生成键的“Hi”部分的下一个值。您可以选择为每个实体表创建单独的列、将由所有实体使用的单个列或两个选项的组合。

如果使用共享列,则每个生成的键将仅由单个实体使用。如果有很多实体表,这可能更可取,但它会减少可以生成的 Id 总数。

例如,我们的项目使用一个HiLoLookup包含三列的表:

NextEntityId BIGINT NOT NULL,
NextAuthenticationLogId BIGINT NOT NULL,
NextConfigurationLogId BIGINT NOT NULL

日志表有大量的插入,因此被赋予了一个单独的 Hi 值池。我们常规实体表的主键列使用 64 位BIGINT数据类型,因此即使 id 序列存在较大间隙,也不存在溢出的危险。共享 ID 池用于减少管理开销。

hi-lo 生成器没有内置支持使用与现有键不冲突的起始值初始化自身 - 所以这需要手动执行。用作起始“hi”值的值取决于几个考虑因素:

  • 最大现有 id 值 - 生成的 id 需要高于此值以避免重复
  • 在从 db ( ) 请求新的“hi”值之前应该生成多少个 id max_lo- 较大的值会提高并发性,但会增加 id 被浪费的可能性,尤其是在服务频繁重启的情况下

max_lo在确定您的起始“hi”值应该是什么时,实体映射中提供的值至关重要。例如,考虑一个表,最大现有id值为12345,回数据库前应该生成的id个数是1000。这种情况下,起始hi值应该是(12345 / 1000) + 1 = 13,第一个生成的id会是13000 . 由于 HiLoGenerator 实现中的一个怪癖,实体配置中提供max_lo值需要是 999,而不是1000

如果使用.hbm映射:

<generator class="hilo">
    <param name="table">dbo.HiLoLookup</param>
    <param name="column">NextEntityId</param>
    <param name="max_lo">999</param>
</generator>
于 2012-05-31T05:31:10.807 回答
1

除了传统的 HiLo,您可能还想研究新的增强型 id 生成器。它们可以使用与 HiLo 工作方式在本质上相似的表(或序列,如果数据库支持),但内置支持不同实体的单独数字序列(如果需要)。使用增强的 id 生成器,您还可以选择使用 HiLo 算法或池化算法。“池化”的好处是 id 生成器表显示的是实际值,而不仅仅是其中的一部分。

这些是 NHibernate 3.3 中的新功能。参考文档还没有提到它们,但是 Hibernate 文档有。它们在 NHibernate 中的工作方式相同。

于 2012-06-01T11:21:44.753 回答
0

我更喜欢使用 HILO,因为它不会破坏 UOW,并且允许我向服务器发送多个插入语句。

现在为您的问题:-

NHibernate 会自动为我在 hi-lo 表中创建行,还是我需要手动编写这些脚本?

您将需要创建您的 hilo 表,hilo 有两种风格,您的所有表中的单个数字或任何表的数字。我更喜欢后者。

如果 NHibernate 确实自动插入行,它是否正确考虑了现有的键值?

您需要手动设置 maxhi/maxlo,lo 位于映射中,hi 位于表中,因此您需要将 XML 映射更改为:-

<id name="Id" column="Id" unsaved-value="0">
    <generator class="hilo">
        <param name="column">NextHi</param>
        <param name="where">TableName='CmsLogin'</param>
        <param name="max_lo">100</param>
    </generator>
</id>

然后可以(手动)生成以下 SQL:-

CREATE TABLE hibernate_unique_key (
  TableName varchar(25) NOT NULL,
  NextHi bigint NOT NULL
)

然后为您希望使用 hilo 的每个表在数据库中添加一行:例如

CmsLogin,123
Address, 456

请注意,这里的 123 将开始我的下一个插入 id 到 (123 x 100) = 12300 因此只要 12300 大于我当前的身份,那么一切都应该是好的!

如果你不喜欢默认的表名hibernate_unique_key,那么你可以把它混在一起

<param name="table">HiloValues</param>
于 2012-05-31T04:30:24.913 回答