15

我使用的数据库严重依赖于标识列。然而,由于我们现在已经将所有应用程序转移到 NHibernate,我想研究一下使用 HiLo,这似乎是 NHibernate 推荐的。有什么策略可以做到这一点,或者有什么常见的问题需要注意吗?

4

5 回答 5

14

您需要设置 NH 使用的表以正确创建 HiLo 值。让 Schema Creator 根据您的映射定义创建表,根据数据库中 id 的当前状态设置值。

我相信(您需要验证这一点) hilo 生成的值是通过以下方式计算的:

hilo-id = high-value * max_lo + low-value

高值存储在数据库中,max_low 定义在映射文件中,低值在运行时计算。


NHibernate 也需要自己的连接和事务来确定和增加高值。因此,如果连接是由应用程序提供的,它就不起作用。

您仍然可以使用seqhilo, NH 使用数据库序列来创建下一个高值,并且不需要单独的连接来执行此操作。这仅适用于支持序列的数据库,如 Oracle。


更正:

同时,我必须自己实现它(之前,这只是理论:-)。所以我回来分享细节。

公式为:

next_hi = (highest_id / (maxLow + 1)) + 1

next_hi是您需要更新的数据库中的字段。highest_id是在您的数据库中找到的最高 ID。maxLow是您在映射文件中指定的值。不知道为什么它会加一。除法是截断小数位的整数除法。

于 2009-10-05T12:40:48.227 回答
8

如果这是一个关于将现有应用程序迁移到以前使用自动 ID 的 hilos 的问题,并且其中有需要迁移的旧数据......那么这将是我最好的选择(虽然没有尝试过! - 欢迎评论!) :

  • 将您的列类型 ID 更改为 bigints
  • 找出当前在任何表中的最高 id 值。
  • 将 hilo 源表中的“下一个高”值设置为高于您在 ID 中找到的值

如果这当然只解决了身份列的问题,而不是在您将应用程序移动到 NHibernate 时可能需要更改的架构中的任何其他内容。

于 2009-10-08T12:42:07.447 回答
0

这是一个脚本(MS SQL),它将用当前数据库中所有表的所有下一个高数字填充 HiLo(Name,Value) 表:

declare tables cursor for

    select
        Table_Schema,
        Table_Name
    from
        information_schema.tables
    where
        Table_Schema = 'dbo'
        and
        Table_Type = 'BASE TABLE'
        and
        Table_Name <> 'HiLo'
        and
        right (Table_Name, 1) <> '_'

declare @table_schema varchar(255)
declare @table_name varchar(255)

truncate table HiLo

open tables
fetch next from tables into @table_schema, @table_name

while (@@fetch_status = 0)
begin
    declare @sql as nvarchar(max)
    declare @max_id as int

    set @sql = 'select @max_id = max(Id) from [' + @table_schema + '].[' + @table_name + ']'
    exec sp_executesql @sql, N'@max_id int output', @max_id output

    declare @max_low as int
    set @max_low = 1000

    declare @next_high as int
    set @next_high = isnull (@max_id / @max_low + 1, 0)

    --select @table_name, @max_id, @next_high
    insert into HiLo (Name, Value) values (@table_schema + '.' + @table_name, @next_high)

    fetch next from tables into @table_schema, @table_name
end

close tables
deallocate tables

select * from HiLo
于 2013-06-26T10:43:35.280 回答
0

我写了一个脚本(基于斯蒂芬斯的回答)来修复 hilo 值(在 sql server 上) - 它假设你有一个 hilo 表

CREATE TABLE [dbo].[HiloValues](
    [next_hi] [int] NULL,
    [Entity] [varchar](128) NOT NULL
)

并且您的表的标识列都称为 ID。使用要为其生成 hilo 值的表名初始化实体表。运行脚本将生成一系列更新语句,如下所示:

UPDATE hv 
SET next_hi = Transactions.ID/(10 + 1) + 1 
FROM HiloValues hv 
CROSS JOIN (SELECT ISNULL(Max(ID), 0) as id FROM Transactions) as Transactions
WHERE hv.entity = 'Transactions'

这里是

DECLARE @scripts TABLE(Script VARCHAR(MAX))
DECLARE @max_lo VARCHAR(MAX) = '10';

INSERT INTO @scripts
SELECT '
UPDATE hv 
SET next_hi = ' + Entity + '.ID/(' + @max_lo + ' + 1) + 1 
FROM HiloValues hv 
CROSS JOIN (SELECT ISNULL(Max(ID), 0) as id FROM ' + entity + ') as ' + entity + '
WHERE hv.entity = ''' + entity + '''' as script 
FROM HiloValues WHERE Entity IN (SELECT  name from sys.tables)



DECLARE curs CURSOR FOR SELECT * FROM @scripts
DECLARE @script VARCHAR(MAX)

OPEN curs 
FETCH NEXT FROM curs INTO @script

WHILE @@FETCH_STATUS = 0
BEGIN
    PRINT @script --OR EXEC(@script)
    FETCH NEXT FROM curs INTO @script
END
CLOSE curs
DEALLOCATE curs
于 2012-03-01T11:24:58.253 回答
0

这是最近从增量生成器迁移到MultipleHiLoPerTableGenerator的示例(例如,单个表用于存储每个实体的高值)。

我的应用程序正在使用 Hibernate 3 + 映射文件 (.hbm.xml)。我的数据库是 MySQL(innoDB + auto increment pk)。

第 1 步:替换 .hbm 文件中的生成器设置。代替 :

<generator class="increment" />

经过

<generator class="org.hibernate.id.MultipleHiLoPerTableGenerator">
    <param name="table">hilo_values</param>
    <param name="primary_key_column">sequence_name</param>
    <param name="value_column">sequence_next_hi_value</param>
    <param name="max_lo">1000</param>
</generator>

第 2 步:创建一个新表来存储高值

CREATE TABLE IF NOT EXISTS `hilo_values` (
  `sequence_name` varchar(255) NOT NULL,
  `sequence_next_hi_value` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

第 3 步:根据现有数据使用以下 SQL 填充初始高值。我在这里假设max_lo每个表都使用相同的值。

INSERT INTO hilo_values SELECT TABLE_NAME,  ((AUTO_INCREMENT DIV (1000 + 1)) + 1) FROM information_schema.tables WHERE table_schema = 'yourdbname'
于 2013-04-16T15:06:49.293 回答