Nous connaissons tous le comportement par défaut d'Hibernate lors de l'utilisation de @SequenceGenerator
- il augmente la séquence réelle de la base de données de un multiple de cette valeur par 50 (par défaut) allocationSize
) - et utilise ensuite cette valeur comme identifiant de l'entité.
Ce comportement est incorrect et entre en conflit avec spécification qui dit :
allocationSize - (Facultatif) Le montant à incrémenter lors de l'allocation des numéros de séquence de la séquence.
Pour être clair : je ne me préoccupe pas des écarts entre les identifiants générés.
Je m'intéresse aux identifiants qui sont pas de cohérence avec la séquence de base de données sous-jacente. Par exemple, toute autre application (qui utilise par exemple JDBC) peut vouloir insérer de nouvelles lignes sous les ID obtenus à partir de la séquence - mais toutes ces valeurs peuvent être déjà utilisées par Hibernate ! La folie.
Est-ce que quelqu'un connaît une solution à ce problème (sans paramétrer allocationSize=1
et donc une dégradation des performances) ?
EDITAR:
Pour que les choses soient claires. Si le dernier enregistrement inséré avait un ID = 1
alors HB utilise les valeurs 51, 52, 53...
pour ses nouvelles entités MAIS en même temps : la valeur de la séquence dans la base de données sera fixée à 2
. Ce qui peut facilement conduire à des erreurs lorsque d'autres applications utilisent cette séquence.
D'autre part, la spécification indique (d'après ce que j'ai compris) que la séquence de la base de données aurait dû être définie comme suit 51
et dans l'intervalle, HB devrait utiliser les valeurs de l'intervalle 2, 3 ... 50
UPDATE :
Comme Steve Ebersole l'a mentionné ci-dessous : le comportement que j'ai décrit (et qui est aussi le plus intuitif pour beaucoup) peut être activé en paramétrant hibernate.id.new_generator_mappings=true
.
Merci à vous tous.
UPDATE 2 :
Pour les futurs lecteurs, vous trouverez ci-dessous un exemple fonctionnel.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USERS_SEQ")
@SequenceGenerator(name = "USERS_SEQ", sequenceName = "SEQUENCE_USERS")
private Long id;
}
persistance.xml
<persistence-unit name="testPU">
<properties>
<property name="hibernate.id.new_generator_mappings" value="true" />
</properties>
</persistence-unit>
4 votes
"sans mettre allocationSize=1 et donc dégrader les performances" pourquoi dégrader les performances si vous le mettez à 1 ?
3 votes
@sheidaei voir mai commentaire ci-dessous :-) C'est parce que chaque
save
doit interroger la base de données pour connaître la valeur suivante de la séquence.0 votes
Merci, j'étais confronté au même problème. Au début, j'ajoutais allocationSize = 1 à chaque @SequenceGenerator. L'utilisation de hibernate.id.new_generator_mappings=true empêche cela. Bien que JPA interroge toujours la base de données pour obtenir l'identifiant pour chaque insertion ...
1 votes
Avec
SequenceGenerator
Hibernate interrogera la base de données uniquement lorsque le nombre d'identifiants spécifié parallocationsize
s'épuise. Si vous mettez en placeallocationSize = 1
alors c'est la raison pour laquelle Hibernate interroge la base de données à chaque insertion. Changez cette valeur, et vous avez terminé.1 votes
Merci !
hibernate.id.new_generator_mappings
Le cadre est vraiment important. J'espère qu'il s'agit du paramètre par défaut pour ne pas avoir à passer autant de temps à chercher pourquoi le numéro d'identification s'emballe.0 votes
Pour que l'exemple de travail fonctionne effectivement, dois-je créer ma séquence avec le paramètre "INCREMENT BY 50" ? Ou est-ce que cela est géré automatiquement par Hibernate ?
0 votes
Définissez le paramètre 'hibernate.id.sequence.increment_size_mismatch_strategy' pour remplacer la valeur par défaut dans le code, puis tous les paramètres seront lus à partir de la base de données.
0 votes
À partir d'Hibernate 5.0
hibernate.id.new_generator_mappings
est définie par défaut à true Guide d'utilisation de l'hibernation