Hibernation avec séquence Oracle ne l'utilise pas

j'ai configuré hibernate pour utiliser la séquence oracle. Sequence est créée avec cache = 20, increment = 1.

Tout fonctionne bien, les entités hibernées persistent. 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 de dual) j'obtiens la valeur comme 2,3,4 ....

si j'allume le débogage de sql hibernate, il y a le temps d'appeler "sélectionner hibernate_sequence.nextval de dual " mais le numéro assigné par hibernation à ID ne se transmet pas par 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
demandé sur Vlada 2011-08-24 11:01:02

3 réponses

C'est parce que le 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 la première fois qu'il est invoqué, 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 invoqué, il renvoie 301 (sans aller à la séquence), et ainsi de suite jusqu'à ce qu'il atteigne 349. Puis il demande la séquence pour la valeur suivante et obtient 7, qu'il multiplie par 50 de nouveau pour vous donner 350. Ma description de l'algorithme pourrait être désactivée d'un, mais vous avez l'idée.

si vous arrêtez et démarrez votre application, il y aura donc des lacunes. Mais c'est plus efficace qu'un simple générateur de séquences car il ne fait appel à une base de données qu'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/en-US/html_single/#mapping-declaration-id-generator pour plus de détails.

32
répondu JB Nizet 2011-08-24 07:22:21

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 lacunes:

Un peu de contexte:

  • Chaque fois que vous appelez select HIBERNATE_SEQUENCE.nextval from DUAL la valeur de la séquence est augmenté.
  • comme votre nom de séquence est générique plutôt que spécifique à la table, si vous avez plusieurs entities qui utilisent toutes HIBERNATE_SEQUENCE comme générateur d'id, alors les valeurs des séquences sont utilisées toutes les entités.
  • si une autre application utilise HIBERNATE_SEQUENCE, alors la valeur est également sautée.
  • comme vous utilisez CACHE=20, Oracle va saisir des numéros de séquence dans des blocs de 20 et ensuite utiliser un cache interne pour retourner les numéros. Cela peut conduire à des nombres omis si le cache est perdu (par exemple si le DB est arrêté).
  • si les 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 entities Entity1 et Entity2 utilisant HIBERNATE_SEQUENCE comme générateur D'ID:

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

Donc à la fin vous allez avoir:

  • l'entité1 IDs (101, 105)
  • Entity2 IDs (102, 106)

ce qui explique les écarts.

EDIT:

même si le @SequenceGenerator ont été mis en place pour utiliser le SequenceGenerator plutôt que SequenceHiLoGenerator (comme l'a souligné JB Nizet, ce qui est une meilleure explication pour les lacunes), les lacunes dans les ID générés par les séquences sont un phénomène courant.

6
répondu beny23 2011-08-24 07:41:27
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
répondu Yogi 2016-07-28 19:31:12