obtenir la prochaine valeur de la séquence à partir de la base de données de l'utilisation d'hibernate
J'ai une entité qui a un champ ID qui doit être défini à partir d'une séquence.
Actuellement, j'ai chercher pour la première valeur de la séquence, de le stocker sur le client, et de calculer à partir de cette valeur.
Cependant, je suis à la recherche d'une "meilleure" manière de faire. J'ai mis en place un moyen pour aller chercher de la prochaine valeur de la séquence:
public Long getNextKey()
{
Query query = session.createSQLQuery( "select nextval('mySequence')" );
Long key = ((BigInteger) query.uniqueResult()).longValue();
return key;
}
Cependant, cela réduit les performances de manière significative (création d' ~5000 objets est ralenti par un facteur de 3 - de 5740ms à 13648ms ).
J'ai essayé d'ajouter un "faux" entité:
@Entity
@SequenceGenerator(name = "sequence", sequenceName = "mySequence")
public class SequenceFetcher
{
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
private long id;
public long getId() {
return id;
}
}
Toutefois, cette approche ne fonctionne pas non plus (tous les Id ont été retournés 0).
Quelqu'un peut me conseiller comment faire pour récupérer la séquence suivante de la valeur de l'utilisation d'Hibernate efficacement?
Edit: Après enquête, j'ai découvert que l'appelant Query query = session.createSQLQuery( "select nextval('mySequence')" );
est de loin la plus inefficace que l'utilisation de la @GeneratedValue
- en raison de Hibernate en quelque sorte parvient à réduire le nombre d'extractions lors de l'accès à la séquence décrite par @GeneratedValue
.
Par exemple, lors de la création de 70 000 entités, (donc avec 70 000 clés primaires récupérée à partir de la même séquence), j'ai tout ce dont j'ai besoin.
CEPENDANT , Hibernate seulement les questions 1404 select nextval ('local_key_sequence')
commandes. NOTE: Sur la base de données côté, la mise en cache est mis à 1.
Si j'essaie de récupérer toutes les données manuellement, il va me prendre de 70 000 sélectionne, donc une énorme différence dans la performance. Personne ne sait le fonctionnement interne de mise en veille prolongée, et comment le reproduire manuellement?
Vous devez vous connecter pour publier un commentaire.
Voici ce qui a fonctionné pour moi (spécifique à Oracle, mais à l'aide de
scalar
semble être la clé)Merci pour les affiches ici: springsource_forum
Vous pouvez utiliser Hibernate Dialecte de l'API de Base de données de l'indépendance comme suit
DatabaseMetaDataDialectResolutionInfoAdapter
pour envelopper le résultat deconnection.getMetaData()
avant de passer àresolveDialect()
. @punitpatel merci!dialect.getSequenceNextValString()
, qui ne fonctionnera pas pour les bases de données ne supportant pas les séquences...doReturningWork
(qui peut être plus récente que 3) aussi,getSequenceNextValString(...)
ne cite pas, ou vérifier le nom de la séquence, et n'est vulnérable à l'injection au moment de ce commentaire. Afin de ne pas obtenir le nom de la séquence à partir de la saisie de l'utilisateur, ce qui est assez peu probable, de toute façon.J'ai trouvé la solution:
Si vous utilisez Oracle, pensez à spécifier la taille du cache de la séquence. Si vous êtes régulièrement créer des objets dans des lots de 5K, vous pouvez simplement le mettre à un 1000 ou 5000. Nous l'avons fait pour la séquence utilisée pour la substitution de la clé primaire et ont été surpris de voir que des temps d'exécution pour un processus ETL écrite à la main en Java a chuté de moitié.
Je ne pouvais pas coller formaté code en commentaire. Voici la séquence DDL:
Pour obtenir la nouvelle carte d'identité, tout ce que vous avez à faire est de
flush
le gestionnaire de l'entité. VoirgetNext()
méthode ci-dessous:SequenceFetcher
POSTGRESQL
MYSQL
Intéressant cela fonctionne pour vous. Quand j'ai essayé votre solution une erreur est survenue, en disant que "incompatibilité de Type: impossible de convertir de SQLQuery de Requête". --> Donc ma solution ressemble:
Avec cette solution je n'ai pas rencontré de problèmes de performance.
Et n'oubliez pas de réinitialiser votre valeur, si vous voulais juste savoir à des fins d'information.
Ici est la façon dont je le fais:
Votre idée avec le SequenceGenerator faux entité est bon.
Il est important d'utiliser le paramètre le nom de la clé "sequence_name". Exécuter une session de débogage sur les hibernate classe SequenceStyleGenerator, la configuration de la(...) méthode à la ligne finale QualifiedName sequenceName = determineSequenceName( params, le dialecte, jdbcEnvironment ); pour voir plus de détails sur la façon dont le nom de la séquence est calculée par Hibernate. Il y a quelques défauts de là, vous pouvez également utiliser.
Après le faux de l'entité, j'ai créé un CrudRepository:
Dans la Junit, j'ai appeler la méthode save de la SequenceRepository.
SequenceGenerator sequenceObject = new SequenceGenerator();
SequenceGenerator résultat = sequenceRepository.enregistrer(sequenceObject);
Si il ya une meilleure façon de le faire (peut-être un soutien pour un générateur sur tout type de terrain au lieu de simplement l'Id), je serais plus qu'heureux de l'utiliser à la place de ce "truc".
Printemps 5 a certains builtin classes d'aide pour:
org/springframework/jdbc/support/incrementer