web-dev-qa-db-fra.com

hibernate Oracle séquence produit grand écart

J'utilise Hibernate 3, Oracle 10g. J'ai une table: sujet. La définition est ici

CREATE TABLE SUBJECT
    ( 
     SUBJECT_ID NUMBER (10), 
     FNAME VARCHAR2(30)  not null, 
     LNAME VARCHAR2(30)  not null, 
     EMAILADR VARCHAR2 (40),
     BIRTHDT  DATE       not null,
     constraint pk_sub primary key(subject_id) USING INDEX TABLESPACE data_index
    ) 
;

quand insérer un nouveau sujet, sub_seq est utilisé pour créer un identifiant de sujet, la définition est ici

create sequence sub_seq
       MINVALUE 1 
       MAXVALUE 999999999999999999999999999 
       START WITH 1
       INCREMENT BY 1 
       CACHE 100 
       NOCYCLE ;

la classe Subject est comme ceci:

@Entity
@Table(name="ktbs.syn_subject")
public class Subject {

    @Id 
    @Column(name="subject_id")
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ")
    @SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ")
    private long subjectId;
    private String fname;
    private String lname;
    private String emailadr;
    private Date birthdt;
}

dans la table subject, 4555 sujets dans la base de données ont été chargés par des scripts plsql à partir d'Excel et la sous-séquence a bien fonctionné. Les identifiants de sujets vont de 1 à 4555.

cependant, lorsque j'ai ajouté un sujet de mon application utilisant hibernate, le numéro de séquence est passé à 255050. Après plusieurs jours d'exécution, les identifiants de sujet générés par hibernate ressemblent à ceci

270079
270078
270077
270076
270075
270074
270073
270072
270071
270070
270069
270068
270067
270066
270065
270064
270063
270062
270061
270060
270059
270058
270057
270056
270055
270054
270053
270052
270051
270050
265057
265056
265055
265054
265053
265052
265051
265050
260059
260058
260057
260056
260055
260054
260053
260052
260051
260050
255067
255066
255065
255064
255063
255062
255061
255060
255059
255058
255057
255056
255055
255054
255053
255052
255051
255050
4555
4554
4553
.
.
.
.
1

Il existe plusieurs lacunes importantes: 4555 à 255051, 255067 à 260051, 265057 à 270051

c'est un gaspillage et non un comportement souhaité.

est-ce que quelqu'un sait pourquoi cela arrive et chaud pour le réparer

Merci

29
sse

Je pense que le problème vient du fait que le générateur de séquence n’est pas vraiment un générateur de séquence mais un générateur de séquence hilo, avec une taille d’allocation par défaut de 50. comme indiqué dans la documentation: http: //docs.jboss org/hibernate/stable/annotations/reference/fr/html_single/# entity-mapping-identifier

Cela signifie que si la valeur de la séquence est 5000, la prochaine valeur générée sera 5000 * 50 = 250000. Ajoutez la valeur de cache de la séquence à l'équation, et cela pourrait expliquer votre énorme écart initial. 

Vérifiez la valeur de la séquence. Il devrait être inférieur au dernier identifiant généré. Veillez à ne pas réinitialiser la séquence à cette dernière valeur générée + 1, car la valeur générée augmenterait de façon exponentielle (nous avons eu ce problème et des ids entiers négatifs dus à un dépassement de capacité).

40
JB Nizet

D'accord avec JB. Mais toujours grâce à PaulJ.

Pour être plus spécifique à mon code d'annotation ci-dessous:

@Entity
@Table(name="ktbs.syn_subject")
public class Subject {

  @Id 
  @Column(name="subject_id")
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SUB_SEQ")
  @javax.persistence.SequenceGenerator(name="SUB_SEQ", sequenceName = "SUB_SEQ")
  private long subjectId;
  private String fname;
  private String lname;
  private String emailadr;
  private Date birthdt;
}

Si vous utilisez javax.persistence.SequenceGenerator, hibernate utilisez hilo et risque de créer de grands espaces dans la séquence. Il existe un message traitant de ce problème: https://forum.hibernate.org/viewtopic.php?t=973682

Il y a deux façons de résoudre ce problème

  1. Dans l'annotation SequenceGenerator, ajoutez allocationSize = 1, initialValue= 1
  2. au lieu d'utiliser javax.persistence.SequenceGenerator, utilisez org.hibernate.annotations comme ceci:

    @javax.persistence.SequenceGenerator(
        name = "Question_id_sequence", 
        sequenceName = "S_QUESTION"
    )
    
    @org.hibernate.annotations.GenericGenerator(
        name="Question_id_sequence", 
        strategy = "sequence", 
        parameters = { 
            @Parameter(name="sequence", value="S_QUESTION") 
        }
    )
    

J'ai testé les deux méthodes, ce qui fonctionne très bien.

36
sse

Une autre solution est:

Utilisez 'GenerationType.AUTO' au lieu de 'GenerationType.SEQUENCE' comme stratégie pour @GeneratedValue, comme ci-dessous;

@Id
@SequenceGenerator(name = "studentId", sequenceName = "student_Id")
@GeneratedValue(strategy = GenerationType.AUTO, generator="studentId")  
private int studentId;
6
Jaydip Halake

En réalité, avoir allocationSize = 1 est acceptable si votre séquence INCREMENT VALUE est égale à 1 et que vous n'avez pas besoin de conserver de nombreuses entités. Cependant, si vous souhaitez conserver des milliers ou des millions d'enregistrements , le paramètre ci-dessus pourrait devenir un goulot d'étranglement des performances puisque chaque sauvegarde doit extraire un identifiant et nécessite par conséquent une lecture de la base de données. 

Pour résoudre ce problème, nous devons définir la variable allocationSize à quelque chose comme 500 et la séquence INCREMENT VALUE dans la base de données également à 500, puis le plus important d'ajouter un paramètre hibernate hibernate.id.new_generator_mappings pour lui demander d'utiliser la nouvelle implémentation du générateur de séquence. propriétés dans une classe de configuration Java: 

properties.setProperty("hibernate.id.new_generator_mappings", Boolean.toString(true));

De cette façon, Hibernate utilisera SequenceStyleGenerator plutôt que l'ancien SequenceHiLoGenerator pour générer les identifiants. La SequenceStyleGenerator est plus compatible JPA et Oracle. Il génère des valeurs d'identifiant basées sur une structure de base de données de type séquence. Les variations vont de l’utilisation réelle d’une séquence à l’utilisation d’un tableau pour imiter une séquence. 

Regardez mon post pour plus de détails si vous êtes dans le même bateau: 

vcfvct.wordpress.com/2016/04/23/jpa-sequencegenerator-with-allocationsize-1-performance-tuning/

6
Leon li

Si vous lisez le lien suivant, vous verrez que le problème est dû au paramètre CACHE de votre commande de création de séquence. La suppression du paramètre de cache résoudra le problème dans une certaine mesure - mais ne tient pas compte de la possibilité de restaurations, etc.

Lien est: http://asktom.Oracle.com/pls/apex/f?p=100:11:::::P11_QUESTION_ID:369390500346406705

La seule façon de resynchroniser vos séquences maintenant consiste à la recréer, à renommer la table actuelle et à la recréer, puis à réinsérer les enregistrements de l'ancienne table dans la nouvelle table.

REMARQUE: La valeur de cache pour les séquences est utile pour les charges importantes où les valeurs de séquence 'x' sont allouées en une fois. Si vous utilisez un système de transaction dans lequel vous ne faites qu'une insertion à la fois, la mise en cache n'est pas utile (ou devrais-je dire, je ne l'ai jamais trouvée utile).

REMARQUE: Ceci est ma compréhension de l'option de cache pour les séquences. Vous pouvez consulter la documentation Oracle sur les commandes CREATE SEQUENCE pour plus d'informations. Mais le lien ci-dessus devrait fournir une réponse raisonnable à votre question.

Merci . Paul

5
PaulJ

Une solution à cela consiste à configurer le générateur de séquence avec allocationSize comme suit:

@SequenceGenerator(name = "gen_name", sequenceName = "seq_name", allocationSize= 1)
2
Shekhar Khairnar

J'ai eu des problèmes similaires. le générateur de séquence et le générateur de séquence hilo sont assez similaires mais présentent des différences. Dans hibernate 3, le générateur hilo se multiplie avec la valeur par défaut 50. Il n'est donc pas nécessaire d'incrémenter la séquence de bases de données. Par contre, les versions ultérieures de hibernate utilisent par défaut le générateur de séquence. Par conséquent, un incrément de base de données de 50 est requis.

_ { https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.3/html/Migration_Guide/Preserve_the_Existing_Behavior_du_Hibernate_Identity_Auto_Generated_Value1.html

J'ai eu ce problème qui ont plusieurs versions de veille prolongée (3 et 5). Même configuration a bien fonctionné (incrémenté de 1 dans la base de données). Mais échoué dans hibernate 5. Par conséquent, je mets à jour mon persistence.xml comme ci-dessous. Cela garantit la génération hilo

        <property name="hibernate.id.new_generator_mappings" value="false" />
1
Olcay Tarazan

La réponse la plus réussie serait:

@Id
@SequenceGenerator (name = "id_sequence", sequenceName = "sq50")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "id_sequence")
public int getId() {
return id;
}
1

Comme dit ici , essayez d’ajuster votre SequenceGenerator.allocationSize avec votre numéro de séquence de base de données INCREMENT BY.

0
Anthony O.