web-dev-qa-db-ja.com

JPA GenerationType.AUTOは、自動インクリメントの列を考慮していません

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型は自動インクリメント動作を使用する必要があるため、なぜ機能しないのかわかりません。

更新:

少し時間がかかりましたが、何が起こっているのかを正確に理解することができました。

私は次の動作でレガシーデータベースを使用しています。

  • MSSQL:ID生成はテーブルIDENTITYを使用します
  • Oracle:ID生成はトリガーを使用します。トリガーは、すべての「次のID」が格納されているカスタムテーブルを照会および更新します。このテーブルはSEQと呼ばれます。

いくつかのID生成戦略を使用した結果は次のとおりです。

  • AUTO:上で説明したように、MSSQLでは機能しません
  • IDENTITY:MSSQLで機能しますが、Oracleではサポートされていません
  • 「ネイティブ」:MSSQLでは機能しますが、Oracleでは失敗します。 Hibernateがhibernate_sequences.nextvalを使用するデフォルトのシーケンス戦略をアクティブ化するため、失敗します。これはレガシーアプリケーションであるため、SEQテーブル(上記)とhibernate_sequencesの値は同期されません(その特定のテーブルのSEQの値は6120であり、hibernate_sequences 'は1です。今まで使われていなかったので)。

したがって、私が理解する必要があるのは、そのエンティティを次のように構成する方法です。

  • MSSQLID機能を使用するまたは
  • Oracleを使用する場合、ID変数に値を自動的に設定せず、すべてを既存のトリガーに任せます

これにより、メインエンティティに依存するエンティティを(外部キーを介して)挿入する必要がある場合、Oracleで重大な問題が発生する可能性があります。これは、Hibernateが「外部」トリガーによって生成されたID値を認識しないためです。

10
felipe_gdr

私は同様の問題を抱えていて、これを見つけました 情報 (より深く ここ で説明されています)。

このプロパティをpersistence.xmlファイルに追加すると、問題が修正されました。

<property name="hibernate.id.new_generator_mappings" value="false" />
9

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;
  • idを整数ではなくLongにすると、HBMDDLに主キーの列タイプを処理させることができます。
  • hibernateに「ネイティブ」ジェネレーターの使用を強制する

レガシーシステムがシーケンス値の生成にテーブルを使用し、hilo最適化がこれまで使用されていなかった場合は、テーブル識別子ジェネレーターを使用できます。

@Id
@GeneratedValue(generator = "table", strategy=GenerationType.TABLE)
@TableGenerator(name = "table", allocationSize = 1
)
private Long id;

JPAテーブルジェネレーターを使用することもできます。適切なオプティマイザーを構成していることを確認してください。詳細については、私の Hibernateチュートリアル を確認してください

6
Vlad Mihalcea

なぜなら

@GeneratedValue(strategy = GenerationType.AUTO)

以前のバージョンでは、デフォルトでSequenceStyleGeneratorを使用します

あなたはこれを見なければなりません https://hibernate.atlassian.net/browse/HHH-11014

0
Muhammad Rfeaat