Hibernate с Oracle sequence не использует его

Я настроил hibernate для использования последовательности oracle. Последовательность создается с помощью cache=20, increment=1.

все работает нормально, спящий режим сохраняется сущностей. Значение id странно: 50,51....76,201,202...209,1008,1009,5129,5130 ....

Если я прошу значение последовательности (выберите hibernate_sequence.nextval от dual) я получаю значение как 2,3,4 ....

Если я включаю отладку Hibernate sql, есть время для вызова " выберите hibernate_sequence.nextval от 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;

3 ответов


Это потому, что SequenceGenerator на самом деле не генератор последовательности. Это генератор последовательности hi-lo. Это означает, что при первом вызове он получает следующее значение из последовательности (например, 6), затем умножает это значение на 50 и дает вам результат (300). При следующем вызове он возвращает 301 (не переходя к последовательности) и так далее, пока не достигнет 349. Затем он запрашивает последовательность для следующего значения и получает 7, который он умножает на 50 снова, чтобы дать вам 350. Мое описание алгоритма может быть ошибочным, но вы понимаете идею.

Если вы остановите и запустите приложение, у него будут пробелы. Но это более эффективно, чем генератор чистой последовательности, потому что он делает вызов базы данных только один раз в 50 поколений.

см 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 для деталей.


Я так понимаю, что ваш вопрос заключается в том, что значения столбца ID в базе данных не естественной последовательности, но почему вы видите пробелы:

немного предыстории:

  • каждый раз, когда вы называете select HIBERNATE_SEQUENCE.nextval from DUAL значение последовательности увеличивается.
  • поскольку ваше имя последовательности является общим, а не конкретным для таблицы, если у вас есть несколько сущностей, которые все используют hibernate_sequence в качестве генератора идентификаторов, то значения из последовательностей используются в все субъекты.
  • если какое-либо другое приложение использует HIBERNATE_SEQUENCE, то значение также пропускается.
  • при использовании CACHE=20 Oracle будет захватывать порядковые номера в блоках по 20, а затем использовать внутренний кэш для возврата чисел. Это может привести к пропущенным номерам, если кэш потерян (например, если БД отключена).
  • если строки удаляются из базы данных, значение последовательности не изменится

например, рассмотрим следующий сценарий:

у вас есть две сущности Entity1 и Entity2, использующие HIBERNATE_SEQUENCE в качестве генератора идентификаторов:

  1. текущее значение HIBERNATE_SEQUENCE равно 100
  2. вставляется Entity1 (использует HIBERNATE_SEQUENCE, который возвращает 101)
  3. вставляется Entity2 (использует HIBERNATE_SEQUENCE, который возвращает 102)
  4. вставляется Entity2 (использует HIBERNATE_SEQUENCE, который возвращает 103)
  5. Entity2 с ID 103 является удалено
  6. вы вручную выполнить select HIBERNATE_SEQUENCE.nextval from DUAL (возвращает 104)
  7. вставляется Entity1 (использует HIBERNATE_SEQUENCE, который возвращает 105)
  8. вставляется Entity2 (использует HIBERNATE_SEQUENCE, который возвращает 106)

Итак, в конце его вы будете иметь:

  • Entity1 с идентификаторами (101, 105)
  • Entity2 с идентификаторами (102, 106)

что объясняет пробелы.

EDIT:

даже если @SequenceGenerator были настроены на использование SequenceGenerator, а не SequenceHiLoGenerator (как указал JB Nizet, что я думаю, является лучшим объяснением пробелов), пробелы в идентификаторах, генерируемых последовательностями, являются обычным явлением.


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;