2010-02-11 3 views
1

J'utilise Hibernate avec Spring et DB2. J'utilise des séquences pour générer une clé primaire pour les entités. Toutes les entités utilisent la même séquence HIBERNATE_SEQUENCE, qui est la valeur par défaut d'hibernate.Hibernate et comportement étrange avec des séquences DB2

Le problème est que les valeurs qui aboutissent aux clés primaires sont environ 10 fois plus élevées que celles renvoyées par HIBERNATE_SEQUENCE.

Par exemple cette situation juste après une nouvelle ligne est insérée à TBL:

select max(id) as primary_key, nextval for hibernate_sequence sequence_value from tbl ; 

primary_key sequence_value 
501483661 50148373 

Je dresser la carte clé primaire comme celui-ci, en super classe pour toutes les entités:

@MappedSuperclass 
public class AbstractEntity implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE) 
    private Integer id; 

I'D comme cela, Hibernate utilise les valeurs qu'il récupère à partir de la séquence, et non les valeurs de séquence multipliées par 10. Quelle est la bonne façon de procéder?

Répondre

2

Hibernate semble faire ce qui suit:

lorsqu'Hibernate a besoin d'une clé primaire, il va récupérer la valeur de la séquence. Hibernate génère plusieurs valeurs de clé primaire à partir de valeurs de séquence uniques. Par exemple, Hibernate conservera un compteur interne dont la valeur est ajoutée à la valeur de la séquence pour obtenir la valeur de la clé primaire. Lorsque le compteur interne atteint sa limite, le compteur est réinitialisé, une nouvelle valeur de la séquence est obtenue et le processus de la clé primaire recommence.

Par exemple:

  1. valeur obtenue à partir sequece est 123. La valeur de la séquence obtenue est stockée par session.
  2. Pour la session en cours, les clés primaires générées sont 1230, 1231, 1232, 1233, ..., 1238, 1239. Une valeur de compteur est concaténée à la valeur de séquence obtenue à l'étape 1. Une clé est générée si nécessaire.
  3. Maintenant, le processus de génération de clé primaire commence partout. Aller à 1.

Cela provoque des effets suivants:

    valeur de séquence de base de données
  • est effectivement multiplié par 10
  • Mise en veille prolongée ne doit pas faire une base de données lu pour chaque DB insérer fait. L'algorithme ci-dessus réduit le nombre de lectures de la séquence à 10% (en faisant beaucoup d'insertions en une seule session).
  • toutes les autres applications non-mise en veille prolongée doit utiliser l'algorithme similaire pour générer des clés primaires de l'ordre, sinon il y aura des conflits clé primaire à un moment donné

Pour utiliser hibernate les valeurs réelles obtenues à partir de la séquence, cette cartographie peut être utilisé:

@Id 
@GeneratedValue(generator="hibernate_sequence") 
@GenericGenerator(strategy="sequence", name="hibernate_sequence") 
private Integer id; 
0

Il existe quelques options sur la commande DB2 create sequence qui peuvent affecter ce problème. INCREMENT_BY indique combien augmenter la valeur à chaque appel à nextval. CACHE avec NO_ORDER réserve un certain nombre de valeurs. Ainsi, si plusieurs connexions utilisent la même séquence, elles peuvent obtenir des valeurs plus rapidement, au prix de l'inactivité des valeurs. Je voudrais vérifier pour voir comment la séquence a été créée avant de creuser dans Hibernate. En regardant le code Hibernate, c'est assez simple - regardez DB2Dialect et vous pouvez voir le sql qu'il utilise pour obtenir la valeur de la séquence.

0

Je résolu ce problème mise allocationSize-1 dans l'annotation @SequenceGenerator.

Exemple:

@MappedSuperclass 
public class AbstractEntity implements Serializable { 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_GENERATOR") 
    private Integer id; 

et l'entité:

@SequenceGenerator(name = "SEQ_GENERATOR", sequenceName = "MY_SEQUENCE", allocationSize = 1) 
public class MyEntity extends AbstractEntity { 
Questions connexes