Спящий режим генерирует отрицательные значения id при использовании последовательности

У меня есть класс со следующим определением:

@Id
@SequenceGenerator(name = "SEQ_ACE_WORKERS_QUEUE_STATS_ID", sequenceName = "SEQ_ACE_WORKERS_QUEUE_STATS_ID", allocationSize = 500)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ACE_WORKERS_QUEUE_STATS_ID")
@Column(name = "ID")
private long Id;

Когда мы запускали его на Jboss 4.2.3, он работал нормально и генерировал правильный идентификатор (начиная с 1000 +)

Теперь мы перешли в jboss 7.1.1, и он генерирует отрицательные идентификаторы! (начиная с -498 и поднимаясь)

Любая идея, почему это может случиться?

Ответ 1

Я просто столкнулся с этой проблемой при переходе с JBoss 6.1 на JBoss 7.1.

Согласно документации JBoss AS 7.1 JPA (https://docs.jboss.org/author/display/AS71/JPA+Reference+Guide#JPAReferenceGuide-Persistenceunitproperties),

JBoss 7.1 автоматически устанавливает несколько свойств гибернации. Одно из заданных свойств - hibernate.id.new_generator_mappings, который активирует новые генераторы ID, которые используют разные алгоритмы и не поддерживают обратную совместимость. Установка этого свойства в false в вашем файле persistence.xml приведет к восстановлению поведения старого генератора.

Документация hibernate 4 также содержит информацию о новых генераторах идентификаторов: http://docs.jboss.org/hibernate/core/4.0/manual/en-US/html_single/#mapping-declaration-id-generator.

В документации на гибернацию четко указано, что генераторы новых идентификаторов по умолчанию не включены, но, как отмечено выше, JBoss 7.1 автоматически разрешает их.

Ответ 2

Новое поведение заключается в следующем:

AllocationSize - это диапазон значений первичного ключа, зарезервированных для Hibernate. И выбор seq.nextval из двойника будет выполняться только после того, как спящий режим потребляет этот диапазон первичных ключей.

Итак, вы должны объявить одно и то же значение как для allocationSize (Hibernate), так и для последовательности increment by (DB)

При явном наборе allocationSize=500, например. на Oracle

create sequence SEQ_ACE_WORKERS_QUEUE_STATS_ID
       MINVALUE 1 
       MAXVALUE 999999999999999999999999999 
       START WITH 1
       INCREMENT BY 500 
       NOCACHE 
       NOCYCLE;

В противном случае вы заметите отрицательные значения или ошибки ограничения, возникающие из вашей БД из-за конфликтов первичных ключей.

При перезапуске сервера приложений вы увидите "прыжок" между последним выделенным первичным ключом и "новый" порядковый номер, выбранный при перезапуске.

Заключительный комментарий: значение по умолчанию - 50. Поэтому, если вы не укажете allocationSize на стороне спящего режима, вы должны объявить increment by 50 на стороне БД.

Ответ 3

Настройка hibernate.id.new_generator_mappings на false в моей persistence.xml была только первой частью решения моей проблемы:

Чтобы полностью решить проблему, я добавил allocationSize в 1 в @SequenceGenerator (который я опускал).