hibernate Oracle séquence produit grand écart

J'utilise hibernate 3, oracle 10g. j'ai une table: subject. 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
    ) 
;

Lorsque vous insérez un nouveau sujet, sub_seq est utilisé pour créer un ID 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, il y a eu 4555 sujets dans la base de données chargés par des scripts plsql à partir d'excel et la sub_sequence a bien fonctionné. les identifiants des sujets vont de 1 à 4555.

Cependant, quand j'ai ajouté un sujet de mon application utilisant hibernate, le numéro de séquence a sauté à 255050. Après plusieurs jours d'exécution, les ID 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 y a plusieurs grandes lacunes: 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
demandé sur Douglas B. Staple 2011-03-18 01:38:37

9 réponses

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é par la documentation : http://docs.jboss.org/hibernate/stable/annotations/reference/en/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. Ajouter 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 avions des ID entiers négatifs en raison du débordement)

38
répondu JB Nizet 2011-03-18 12:25:53

D'accord avec JB. Mais encore 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 utilise hilo et créera éventuellement de grands espaces dans la séquence. Il y a un poste abordant 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.persistance.SequenceGenerator, utiliser org.hiberner.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 façons, ce qui fonctionne très bien.

35
répondu sse 2017-05-04 15:29:10

Une autre solution est:

Utilisez ' strategy = GenerationType.AUTO 'au lieu de' strategy = GenerationType.Séquence', comme ci-dessous

@Id
@SequenceGenerator(name = "studentId", sequenceName = "student_Id")
@GeneratedValue(strategy = GenerationType.AUTO, generator="studentId")  
private int studentId;
6
répondu Jaydip Halake 2012-11-22 18:36:47

Avoir réellement allocationSize=1 est bien si votre séquence INCREMENT VALUE est 1 et que vous n'avez pas besoin de persister beaucoup d'entités. Cependant, si vous voulez persister des milliers ou des millions d'enregistrements, le paramètre ci-dessus pourrait devenir un goulot d'étranglement de performance puisque chaque sauvegarde doit récupérer un id et donc avoir besoin d'une lecture db.

Pour résoudre ce problème, nous devons définir le allocationSize à quelque chose comme 500 et la séquence INCREMENT VALUE dans DB également à 500, puis le plus important ajouter un hibernate définir hibernate.id.new_generator_mappings pour lui demander d'utiliser la nouvelle implémentation du générateur de séquences, ici je suppose que vous définissez vos propriétés hibernate dans une classe java Config:

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 ID. Le SequenceStyleGenerator est plus convivial jpa et oracle. Il génère des valeurs d'identifiant basées sur une structure de base de données de style séquence. Les Variations vont de l'utilisation réelle d'une séquence à l'utilisation d'une table pour imiter une séquence.

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

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

6
répondu Leon li 2017-04-13 17:14:13

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

Le lien est: http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:369390500346406705

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

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

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

Merci. Paul

5
répondu PaulJ 2011-03-17 22:45:25

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
répondu Bhabani Sankar Sahoo 2013-05-23 12:14:19

J'ai eu des problèmes similaires. sequence generator et sequence hilo generator sont assez similaires mais ont des différences. Dans hibernate 3, le générateur hilo se multiplie avec la valeur par défaut 50. Par conséquent, pas besoin d'incrémenter la séquence DB. D'autre part, les versions ultérieures d'hibernate utilisent le générateur de séquences par défaut. Par conséquent l'incrément DB de 50 est requis.

Https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.3/html/Migration_Guide/Preserve_the_Existing_Behavior_of_the_Hibernate_Identity_Auto_Generated_Value1.html

J'ai eu ce problème qui a plusieurs versions hibernate (3 et 5). La même configuration a bien fonctionné (incrémentée de 1 en DB). Mais a échoué dans hibernate 5. Par conséquent, je mets à jour ma persistance.xml comme ci-dessous. Cela garantit la génération hilo

        <property name="hibernate.id.new_generator_mappings" value="false" />
1
répondu Olcay Tarazan 2016-06-02 11:45:30

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

0
répondu Anthony O. 2017-05-23 10:31:34

Une solution à cela, nous pouvons configurer le générateur de séquence avec allocationSize comme:

@SequenceGenerator(name = "gen_name", sequenceName = "seq_name", allocationSize= 1)
0
répondu Shekhar Khairnar 2018-08-30 12:05:40