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 в качестве генератора идентификаторов:
- текущее значение HIBERNATE_SEQUENCE равно 100
- вставляется Entity1 (использует HIBERNATE_SEQUENCE, который возвращает 101)
- вставляется Entity2 (использует HIBERNATE_SEQUENCE, который возвращает 102)
- вставляется Entity2 (использует HIBERNATE_SEQUENCE, который возвращает 103)
- Entity2 с ID 103 является удалено
- вы вручную выполнить
select HIBERNATE_SEQUENCE.nextval from DUAL
(возвращает 104) - вставляется Entity1 (использует HIBERNATE_SEQUENCE, который возвращает 105)
- вставляется 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;