代码之家  ›  专栏  ›  技术社区  ›  Jack Ryan

有没有一种从标识列迁移到hilo键的实用方法?

  •  15
  • Jack Ryan  · 技术社区  · 15 年前

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

    5 回复  |  直到 11 年前
        1
  •  7
  •   UpTheCreek    15 年前

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

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

    如果这只解决了标识列的问题,那么在您的模式中,如果您将应用程序移动到nhibernate,则可能需要更改任何其他内容。

        2
  •  14
  •   Stefan Steinegger    11 年前

    您需要设置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 是在映射文件中指定的值。不知道为什么它会增加一个。除法是一个整数单位,它将小数点截断。

        3
  •  0
  •   mcintyre321    12 年前

    我编写了一个脚本(基于stephans answer),用于修复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
    
        4
  •  0
  •   Michael Logutov    11 年前

    下面是一个脚本(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
    
        5
  •  0
  •   anthony_don    11 年前

    这是最近从 增量 发电机至 多导波发生器 (例如,单个表用于存储每个实体的高值)。

    我的应用程序正在使用Hibernate3+映射文件(.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'