web-dev-qa-db-ja.com

Hibernate with Oracleシーケンスはそれを使用しません

Oracleシーケンスを使用するようにhibernateを構成しました。シーケンスはcache = 20、increment = 1で作成されます。

すべてが正常に動作し、休止状態の永続的なエンティティです。 id値が奇妙です:50,51 .... 76,201,202 ... 209,1008,1009,5129,5130 ....

シーケンス値を要求すると(デュアルからhibernate_sequence.nextvalを選択)、2、3、4などの値が得られます。

Hibernate sql debugをオンにすると、「select hibernate_sequence.nextval from dual」が時々呼び出されますが、hibernateによってIDに割り当てられた番号がシーケンスをリレーしません。

@Id
@Column(name = "ID", insertable = false, updatable = false)
@SequenceGenerator(name = "SequenceIdGenerator", sequenceName = "HIBERNATE_SEQUENCE")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SequenceIdGenerator")
private Long id;
21
Vlada

これは、SequenceGeneratorが実際にはシーケンスジェネレータではないためです。シーケンスハイロージェネレーターです。つまり、最初に呼び出されたときに、シーケンスから次の値(たとえば6)を取得し、この値に50を掛けて結果(300)を返します。次に呼び出されると、301に戻り(シーケンスに移動せずに)、349に到達するまで繰り返されます。次に、シーケンスに次の値を要求し、7を取得します。これに50を掛けると350になります。Myアルゴリズムの説明は1つずれる可能性がありますが、アイデアは理解できます。

したがって、アプリケーションを停止して開始すると、ギャップが生じます。ただし、50世代に1回だけデータベース呼び出しを行うため、純粋なシーケンスジェネレーターよりも効率的です。

http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-id-enhanced-optimizers および http:/詳細は/docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-id-generator をご覧ください。

33
JB Nizet

あなたの質問は、データベースのID列の値が自然なシーケンスではないことですが、なぜギャップが生じているのでしょうか。

背景のビット:

  • select HIBERNATE_SEQUENCE.nextval from DUALを呼び出すたびに、シーケンスの値が増加します。
  • シーケンス名はテーブル固有ではなく総称であるため、IDジェネレーターとしてすべてHIBERNATE_SEQUENCEを使用するエンティティが複数ある場合、シーケンスの値はすべてのエンティティで使用されます。
  • 他のアプリケーションがHIBERNATE_SEQUENCEを使用している場合、値もスキップされます。
  • CACHE = 20を使用しているため、Oracleはシーケンス番号を20のブロックで取得し、内部キャッシュを使用して番号を返します。これにより、キャッシュが失われた場合(DBがシャットダウンされた場合など)に番号がスキップされる可能性があります。
  • データベースから行が削除されても、シーケンス値は変化しません

たとえば、次のシナリオを考えます。

IDジェネレーターとしてHIBERNATE_SEQUENCEを使用して、2つのエンティティEntity1とEntity2があります。

  1. 現在のHIBERNATE_SEQUENCE値は100です
  2. Entity1が挿入されます(101を返すHIBERNATE_SEQUENCEを使用します)
  3. Entity2が挿入されます(102を返すHIBERNATE_SEQUENCEを使用します)
  4. Entity2が挿入されます(103を返すHIBERNATE_SEQUENCEを使用します)
  5. ID 103のEntity2が削除されます
  6. 手動でselect HIBERNATE_SEQUENCE.nextval from DUALを実行します(104を返します)
  7. Entity1が挿入されます(105を返すHIBERNATE_SEQUENCEを使用します)
  8. Entity2が挿入されます(106を返すHIBERNATE_SEQUENCEを使用します)

したがって、最後には次のようになります。

  • Entity1とID(101、105)
  • Entity2とID(102、106)

ギャップを説明します。

編集:

@SequenceGeneratorがSequenceGeneratorではなくSequenceHiLoGeneratorを使用するように設定されていたとしても(JB Nizetが指摘したように、ギャップについてはより適切な説明だと思います)、生成されるIDのギャップシーケンスはよくあることです。

6
beny23
CREATE SEQUENCE SEQ_SEQUENCENAME INCREMENT BY 1 START WITH 1 MINVALUE 1;
grant all on SEQ_SEQUENCENAME to public;

@Id
@Column(name = "ID", unique = true, nullable = false)
@SequenceGenerator(name = "SequenceIdGenerator", sequenceName = "SEQ_SEQUENCENAME")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SequenceIdGenerator")
private int Id;
0
Yogi