SQLServerにIDの自動インクリメントを使用した単純なintid列を持つテーブルがあります。
エンティティのIDには、@Id
および@GeneratedValue
の注釈が付けられています
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
SQL Serverでは、列はSeed
およびIncrement
が1に等しいIDとして適切に設定されます。
このエンティティのインスタンスを永続化しようとすると、Hibernateはhibernate_sequenceテーブルにクエリを実行してID値を取得しようとします。スキーマにそのテーブルを作成していないため、エラーが発生します。
could not read a hi value: com.Microsoft.sqlserver.jdbc.SQLServerException: Invalid object name 'MySchema.hibernate_sequence'
世代タイプをIDENTITYに変更すると、すべてが期待どおりに機能します
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", length = 4, precision = 10, nullable = false)
private Integer id;
私のアプリはMSSQLとOracleの両方で実行され、後者は自動インクリメント列をサポートしていないため、この方法で変更することはできません。
私の知る限り、基盤となるデータベースがAUTO型をサポートしている場合、AUTO型は自動インクリメント動作を使用する必要があるため、なぜ機能しないのかわかりません。
更新:
少し時間がかかりましたが、何が起こっているのかを正確に理解することができました。
私は次の動作でレガシーデータベースを使用しています。
いくつかのID生成戦略を使用した結果は次のとおりです。
したがって、私が理解する必要があるのは、そのエンティティを次のように構成する方法です。
これにより、メインエンティティに依存するエンティティを(外部キーを介して)挿入する必要がある場合、Oracleで重大な問題が発生する可能性があります。これは、Hibernateが「外部」トリガーによって生成されたID値を認識しないためです。
Orcale 12cはIDENTITYをサポートし、SQL SERVER2012はSEQUENCESをサポートします。 SEQUENCEは常にIDENTITY よりも良い選択だと思います。 IDENTITYはバッチ処理を無効にし、SEQUENCESを使用すると、 pooled-lo最適化戦略 などのオプティマイザーを提供できます。
これは、構成されたGenerationType値に対して実際の識別子ジェネレーターが選択される方法です。
switch ( generatorEnum ) {
case IDENTITY:
return "identity";
case AUTO:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "native";
case TABLE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.TableGenerator.class.getName()
: MultipleHiLoPerTableGenerator.class.getName();
case SEQUENCE:
return useNewGeneratorMappings
? org.hibernate.id.enhanced.SequenceStyleGenerator.class.getName()
: "seqhilo";
}
新しい識別子ジェネレーター を使用する場合:
properties.put( "hibernate.id.new_generator_mappings"、 "true");
AUTOは実際にはSequenceStyleGeneratorを使用し、データベースがシーケンスをサポートしていない場合は、代わりにTABLEジェネレーターを使用することになります(これは移植可能なソリューションですが、IDENTITYやSEQUENCEよりも効率的ではありません)。
従来の識別子ジェネレーターを使用すると、「ネイティブ」生成戦略になります。つまり、次のようになります。
public Class getNativeIdentifierGeneratorClass() {
if ( supportsIdentityColumns() ) {
return IdentityGenerator.class;
}
else if ( supportsSequences() ) {
return SequenceGenerator.class;
}
else {
return TableHiLoGenerator.class;
}
}
新しいOracle12gDialectが追加され、IDENTITYをサポートする場合、AUTOはSEQUENCEではなくIDENTITYに切り替わる可能性があり、現在の期待を破る可能性があります。現在、そのような方言は利用できないため、OracleではSEQUENCEがあり、MSSQLではIDENTITYがあります。
結論:
このように試してください:
@Id
@GenericGenerator(name = "native_generator", strategy = "native")
@GeneratedValue(generator = "native_generator")
private Long id;
レガシーシステムがシーケンス値の生成にテーブルを使用し、hilo最適化がこれまで使用されていなかった場合は、テーブル識別子ジェネレーターを使用できます。
@Id
@GeneratedValue(generator = "table", strategy=GenerationType.TABLE)
@TableGenerator(name = "table", allocationSize = 1
)
private Long id;
JPAテーブルジェネレーターを使用することもできます。適切なオプティマイザーを構成していることを確認してください。詳細については、私の Hibernateチュートリアル を確認してください
なぜなら
@GeneratedValue(strategy = GenerationType.AUTO)
以前のバージョンでは、デフォルトでSequenceStyleGenerator
を使用します
あなたはこれを見なければなりません https://hibernate.atlassian.net/browse/HHH-11014