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

发布于 2024-08-04 15:00:59 字数 115 浏览 8 评论 0原文

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

I work with a database that depends heavily on identity columns. However as we have now moved all applications over to NHibernate I wanted to look into using HiLo as seems to be recommended with NHibernate. Are there any strategies to do this, or any common problems to watch out for?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

傾旎 2024-08-11 15:01:00

下面是一个脚本 (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

Here's a script (MS SQL) that will fill HiLo(Name,Value) table with all next high numbers for all tables in current database:

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
把昨日还给我 2024-08-11 15:01:00

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

我的应用程序使用 Hibernate 3 + 映射文件 (.hbm.xml)。我的数据库是MySQL(innoDB + 自增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'

Here is a sample from a recent migration from the increment generator to the MultipleHiLoPerTableGenerator (e.g. a single table is used to store high values for every Entities).

My application is using Hibernate 3 + mapping files (.hbm.xml). My database is MySQL (innoDB + auto increment pk).

Step 1 : replace your generator settings in your .hbm files.
Replace :

<generator class="increment" />

By

<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>

Step 2 : create a new table to store the high values

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;

Step 3 : populate the initial high values according to existing data using the following piece of SQL. I assume here that the same max_lo value is used for every table.

INSERT INTO hilo_values SELECT TABLE_NAME,  ((AUTO_INCREMENT DIV (1000 + 1)) + 1) FROM information_schema.tables WHERE table_schema = 'yourdbname'
双马尾 2024-08-11 15:00:59

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

我相信(您需要验证这一点)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 是您在映射文件中指定的值。不知道为什么它会增加一。除法是截断小数位的整数除法。

You need to setup the table used by NH to create HiLo values correctly. Let Schema Creator create the table according to your mapping definitions, set the values according to the current state of the ids in your database.

I believe (you need to verify this) that values generated by hilo are calculated by:

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

While the high-value is stored in the database, max_low defined in the mapping file and low-value calculated at runtime.


NHibernate also needs its own connection and transaction to determine and increment the high value. Therefore it does not work if the connection is provided by the application.

You can still use seqhilo, NH uses a database sequence to create next high-values and does not need a separate connection to do so. This is only available on databases which support sequences, like Oracle.


Correction:

Meanwhile, I had to implement it myself (before, it was just theory :-). So I come back to share the details.

The formula is:

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

next_hi is the field in the database you need to update. highest_id is the highest ID found in your database. maxLow is the value you specified in the mapping file. No Idea why it is incremented by one. The division is an integer devision which truncates the decimal places.

隐诗 2024-08-11 15:00:59

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

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

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

If this is a question about migrating an existing application to hilos which previously used auto ids, and has old data in it which needs to be migrated... then this would be my best bet (not tried it though! - comments welcome!) :

  • Change your column types ids to bigints
  • find out highest id value currently in any table.
  • Set your 'next-high' value in the hilo source table to a value higher than you found in the IDs

If course this only addresses issues with the identity column, not anything else in your schema that might need to change if you are moving an app to NHibernate.

夜清冷一曲。 2024-08-11 15:00:59

我写了一个脚本(基于Stephans的答案)来修复hilo值(在sql服务器上) - 它假设你有一个像这样的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

I wrote a script (based of Stephans answer) for fixing hilo values (on sql server) - it assumes that you have a hilo table like

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

And your table's identity columns are all called ID. Init the Entity table with the table names you want to generate the hilo values for. Running the script will generate a series of update statements like this one:

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'

Here it is

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文