web-dev-qa-db-fra.com

L'utilisation en veille prolongée de la séquence PostgreSQL n'affecte pas la table de séquence

J'ai configuré Hibernate pour utiliser la séquence PostgreSQL (via des annotations) pour générer des valeurs pour la clé primaire id colonne comme suit:

@Id 
@SequenceGenerator(name="pk_sequence",sequenceName="entity_id_seq")
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="pk_sequence")
@Column(name="id", unique=true, nullable=false)
public int getId() {
    return this.id;
}

Ce que je vois avec cette configuration, c'est que hibernate attribue déjà id valeurs> 3000 en persistant, tandis que la requête sur la séquence utilisée montre ce qui suit:

database=# select last_value from entity_id_seq;
last_value 
------------
     69

(1 rangée)

Des questions:
Y a-t-il quelque chose de mal ou non?
La mise en veille prolongée doit-elle être synchronisée avec la table de séquence?
Sinon, où stocke-t-il le dernier identifiant généré?

Je vous remercie.

26
forker

J'ai eu le même problème. Elle est liée aux stratégies d'allocation d'ID de Hibernate. Lorsque vous choisissez GenerationType.SEQUENCE, Hibernate utilise la stratégie HiLo qui alloue les ID par blocs de 50 par défaut. Vous pouvez donc définir explicitement allocationSize valeur comme ceci:

@Id 
@SequenceGenerator(name="pk_sequence",sequenceName="entity_id_seq", allocationSize=1)
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="pk_sequence")
@Column(name="id", unique=true, nullable=false)
public int getId() {
    return this.id;
}

Cependant, j'ai également entendu des avis selon lesquels l'utilisation de la stratégie HiLo avec allocationSize = 1 n'est pas une bonne pratique. Certaines personnes recommandent d'utiliser GenerationType.AUTO à la place lorsque vous devez gérer des séquences gérées par une base de données

Mise à jour: J'ai fini par utiliser allocationSize = 1, et les choses semblent fonctionner comme je m'attends maintenant. Mon application est telle que je n'ai pas vraiment besoin de blocs d'ID de toute façon, donc YMMV .

32
Nofate

N'UTILISEZ PAS GenerationType.SEQUENCE pour les séquences Postgres!

C'est complètement contre-intuitif, mais les gens d'Hibernate ont complètement foiré cela. Vous devez utiliser GenerationType.AUTO ou Hibernate démolirez vos séquences si vous devez redémarrer/reconstruire votre base de données. Il est presque criminellement négligent qu'ils autorisent ce code à entrer dans une version de production, mais l'équipe Hibernate est plutôt célèbre pour ses positions à tête de taureau vers des positions carrément erronées (consultez leur position sur LEFT JOINs, par exemple).

25
Matt Brock

Vous devez d'abord déterminer la version d'Hibernate que vous utilisez. En ce qui concerne les versions hibernate-core, la version 3.2 a introduit une prise en charge plus cohérente des générateurs d'ID, en particulier en ce qui concerne les annotations définies. Voir http://in.relation.to/Bloggers/New323HibernateIdentifierGenerators pour une discussion.

La 3.6 suivante a introduit un paramètre ('hibernate.id.new_generator_mappings') qui fait des générateurs discutés dans ce blog la façon par défaut de gérer les annotations JPA. Le paramètre est faux par défaut car Hibernate doit maintenir la compatibilité descendante avec les anciennes versions. Si vous voulez le nouveau comportement (qui est complètement recommandé), définissez simplement ce paramètre sur true.

La façon dont GenerationType est géré dépend de la version que vous utilisez et de la valeur true de "hibernate.id.new_generator_mappings". Je suppose que vous utilisez 3.6+ (puisque tout ce qui est plus ancien est, eh bien, vieux) et que 'hibernate.id.new_generator_mappings' est défini sur true (puisque c'est la recommandation pour les nouvelles applications):

  1. GenerationType.AUTO -> traité comme GenerationType.SEQUENCE
  2. GenerationType.SEQUENCE -> correspond à la classe org.hibernate.id.enhanced.SequenceStyleGenerator discutée dans le blog
  3. GenerationType.TABLE -> correspond à la classe org.hibernate.id.enhanced.TableGenerator discutée dans le blog
8
Steve Ebersole

Dans Postgres, je ferais ceci:

@Id 
@SequenceGenerator(name="pk_sequence",sequenceName="\"entity_id_seq\"")
@GeneratedValue(strategy=GenerationType.SEQUENCE,generator="\"pk_sequence\"")
@Column(name="\"id\"", unique=true)
private int id;

Surtout avec des noms en majuscules, Hibernate doit passer des guillemets échappés pour comprendre Postgres et trouver les noms des tables, des colonnes ou des séquences.

0
Christian Vielma