web-dev-qa-db-fra.com

La séquence Hibernate avec Oracle ne l'utilise pas

J'ai configuré hibernate pour utiliser la séquence Oracle. La séquence est créée avec cache = 20, incrément = 1.

Tout fonctionne bien, hiberner les entités persistantes. La valeur id est étrange: 50,51 ... 76 201,202 ... 209,1008,1009,5129,5130 .... 

Si je demande une valeur de séquence (sélectionnez hibernate_sequence.nextval parmi dual), je reçois une valeur de 2,3,4 ...

Si j'active le débogage hibernate sql, il est parfois procédé à l'appel "select hibernate_sequence.nextval from dual", mais le numéro attribué par hibernate à ID ne transmet pas la séquence!

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

En effet, SequenceGenerator n'est pas vraiment un générateur de séquence. C'est un générateur de séquence hi-lo. Cela signifie que lors de son premier appel, il obtient la valeur suivante de la séquence (6 par exemple), puis multiplie cette valeur par 50 et vous donne le résultat (300). La prochaine fois qu'il est appelé, il retourne 301 (sans passer à la séquence), et ainsi de suite jusqu'à atteindre 349. Ensuite, il demande à la séquence la valeur suivante et obtient 7, qu'il multiplie par 50 et donne à nouveau 350. Mon La description de l'algorithme peut être décalée de un, mais vous voyez l'idée.

Si vous arrêtez et démarrez votre application, il y aura donc des lacunes. Mais il est plus efficace qu'un générateur de séquence pur, car il effectue un appel de base de données une fois sur 50 générations.

Voir http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#mapping-declaration-id-enhanced-optimizers et http: //docs.jboss. org/hibernate/core/3.6/reference/fr-US/html_single/# mapping-declaration-id-generator pour plus de détails.

32
JB Nizet

Je suppose que votre question est que les valeurs de la colonne ID dans la base de données ne sont pas une séquence naturelle, mais pourquoi vous voyez des lacunes:

Un peu de fond:

  • Chaque fois que vous appelez select HIBERNATE_SEQUENCE.nextval from DUAL, la valeur de la séquence est augmentée.
  • Comme le nom de votre séquence est générique plutôt que spécifique à la table, si vous avez plusieurs entités qui utilisent toutes HIBERNATE_SEQUENCE comme générateur d'identifiant, les valeurs des séquences sont utilisées dans toutes les entités.
  • Si une autre application utilise HIBERNATE_SEQUENCE, la valeur est également ignorée.
  • Comme vous utilisez CACHE = 20, Oracle récupérera les numéros de séquence par blocs de 20, puis utilisera un cache interne pour renvoyer les numéros. Cela peut entraîner l’omission de numéros si la mémoire cache est perdue (par exemple, si la base de données est fermée).
  • Si des lignes sont supprimées de votre base de données, la valeur de séquence ne change pas.

Par exemple, considérons le scénario suivant:

Vous avez deux entités Entity1 et Entity2 utilisant HIBERNATE_SEQUENCE en tant que générateur d'identifiant:

  1. La valeur actuelle de HIBERNATE_SEQUENCE est 100
  2. Une entité1 est insérée (utilise HIBERNATE_SEQUENCE qui renvoie 101)
  3. Une entité2 est insérée (utilise HIBERNATE_SEQUENCE qui renvoie 102)
  4. Une entité2 est insérée (utilise HIBERNATE_SEQUENCE qui renvoie 103)
  5. L'entité2 avec l'ID 103 est supprimée
  6. Vous exécutez manuellement select HIBERNATE_SEQUENCE.nextval from DUAL (renvoie 104)
  7. Une entité1 est insérée (utilise HIBERNATE_SEQUENCE qui renvoie 105)
  8. Une entité2 est insérée (utilise HIBERNATE_SEQUENCE qui renvoie 106)

Donc à la fin, vous aurez:

  • Entité1 avec identifiants (101, 105)
  • Entity2 avec identifiants (102, 106)

ce qui explique les lacunes.

MODIFIER:

Même si le @SequenceGenerator était configuré pour utiliser le SequenceGenerator au lieu du SequenceHiLoGenerator (comme l'a souligné JB Nizet, ce qui est une meilleure explication des lacunes), les lacunes dans les ID générés par les séquences sont courantes.

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