web-dev-qa-db-fra.com

Hibernate génère des valeurs d'ID négatives lors de l'utilisation d'une séquence

J'ai une classe avec la définition suivante:

@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;

Lorsque nous l'avons exécuté sur Jboss 4.2.3, cela a bien fonctionné et généré les ID appropriés (à partir de 1000+)

Maintenant, nous sommes passés à jboss 7.1.1 et il génère des ID négatifs! (à partir de -498 et en remontant)

Une idée pourquoi cela pourrait arriver?

41
Tomer

Je viens de rencontrer ce problème lors de la migration de JBoss 6.1 vers JBoss 7.1.

Selon la documentation JBoss AS 7.1 JPA ( https://docs.jboss.org/author/display/AS71/JPA+Reference+Guide#JPAReferenceGuide-Persistenceunitproperties ),

JBoss 7.1 définit automatiquement plusieurs propriétés d'hibernation. L'une des propriétés définies est hibernate.id.new_generator_mappings qui active de nouveaux générateurs d'ID qui utilisent différents algorithmes et ne sont pas rétrocompatibles. La définition de cette propriété sur false dans votre fichier persistence.xml restaurera l'ancien comportement du générateur d'ID.

La documentation hibernate 4 contient également des informations concernant les nouveaux générateurs d'ID: http://docs.jboss.org/hibernate/core/4.0/manual/en-US/html_single/#mapping-declaration-id-generator .

La documentation de mise en veille prolongée indique clairement que les nouveaux générateurs d'ID ne sont pas activés par défaut, mais, comme indiqué ci-dessus, JBoss 7.1 les active automatiquement.

37
jrm

Le nouveau comportement est le suivant:

AllocationSize est une plage de valeurs de clé primaire réservée à Hibernate. Et sélectionnez seq.nextval à partir du double ne sera effectué qu'après que l'hibernation aura consommé cette plage de clés primaires.

Donc vous devez déclarer la même valeur à la fois sur allocationSize (Hibernate) et sur la séquence increment by (DB)

Lorsque explicitement défini allocationSize=500, par exemple. sur Oracle

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

Sinon, vous remarquerez des valeurs négatives ou des erreurs de contrainte générées à partir de votre base de données en raison de collisions de clés primaires.

Lorsque le serveur d'applications est redémarré, vous remarquerez le "saut" entre la dernière clé primaire allouée et le "nouveau" numéro de séquence sélectionné au redémarrage.

Commentaire final: la valeur par défaut est 50. Donc si vous ne spécifiez pas allocationSize du côté Hibernate, vous devez déclarer increment by 50 côté DB.

78
skay

Réglage hibernate.id.new_generator_mappings à false dans mon persistence.xml n'était que la première partie de la solution à mon problème:

Pour résoudre complètement le problème, j'ai ajouté le allocationSize à 1 dans le @SequenceGenerator (que j'omettais).

24
falsarella