ID列に大きく依存するデータベースを使用しています。ただし、すべてのアプリケーションをNHibernateに移行したので、NHibernateで推奨されているようにHiLoの使用を検討したいと思いました。これを行うための戦略、または注意すべき一般的な問題はありますか?
5 に答える
HiLo値を正しく作成するには、NHが使用するテーブルを設定する必要があります。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
マッピングファイルで指定した値です。なぜそれが1つ増えるのか分かりません。除算は、小数点以下を切り捨てる整数除算です。
これが、以前は自動IDを使用していたhilosに既存のアプリケーションを移行することについての質問であり、移行する必要のある古いデータが含まれている場合は、これが最善の策です(ただし、試していない!-コメントを歓迎します!) :
- 列タイプIDをbigintsに変更します
- 現在任意のテーブルにある最大のID値を見つけます。
- hiloソーステーブルの「next-high」値をIDで見つけた値よりも高い値に設定します
もちろん、これはID列の問題のみに対処し、アプリをNHibernateに移動する場合に変更する必要のあるスキーマ内の他の問題には対処しません。
私は(SQLサーバー上で)hilo値を修正するためのスクリプト(Stephansの回答に基づく)を作成しました-それはあなたが次のようなhiloテーブルを持っていることを前提としています
CREATE TABLE [dbo].[HiloValues](
[next_hi] [int] NULL,
[Entity] [varchar](128) NOT NULL
)
また、テーブルのID列はすべてIDと呼ばれます。hilo値を生成するテーブル名でEntityテーブルを初期化します。スクリプトを実行すると、次のような一連の更新ステートメントが生成されます。
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
これは、増分ジェネレーターからMultipleHiLoPerTableGeneratorへの最近の移行のサンプルです(たとえば、単一のテーブルを使用して、すべてのエンティティの高い値を格納します)。
私のアプリケーションはHibernate3+マッピングファイル(.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'
これは、HiLo(Name、Value)テーブルに、現在のデータベース内のすべてのテーブルの次に大きい数値をすべて入力するスクリプト(MS SQL)です。
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