如何将主键生成从“增量”迁移到“hi-lo”?

时间:2012-05-31 03:25:09

标签: nhibernate migration primary-key

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

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

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

过渡到 hi-lo 生成器似乎是最好的前进方式,但我找不到有关此类迁移如何工作的大量详细信息。

NHibernate是否会自动在hi-lo表中创建行,或者我是否需要手动编写这些行?

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

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

更新

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

为了进行比较,NHibernate identity 生成器通过使用标识列配置数据库表来工作,从而将控制权生成到数据库的手中。这很有效,但会影响工作单元格式。

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

3 个答案:

答案 0 :(得分: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(max_lo)请求新的“hi”值之前应生成多少个id - 更大的值可以提高并发性,但会增加id浪费的可能性,尤其是在频繁重新启动服务的情况下

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

如果使用.hbm映射:

<generator class="hilo">
    <param name="table">dbo.HiLoLookup</param>
    <param name="column">NextEntityId</param>
    <param name="max_lo">999</param>
</generator>

答案 1 :(得分:1)

除了传统的HiLo,您可能还想查看新的增强型ID生成器。这些可以使用一个表(或数据库支持的序列)在精神上与HiLo的工作方式类似,但是对不同实体的单独数字系列的建立支持(如果需要)。使用增强的id生成器,您还可以选择使用HiLo算法或池化算法。 “汇集”的好处是id生成器表显示实际值,而不仅仅是它的一部分。

这些是NHibernate 3.3中的新功能。参考文档尚未提及它们,但Hibernate文档可以。它们在NHibernate中的工作方式相同。

答案 2 :(得分: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>