117 votes

Utilisation correcte de flush() en JPA/Hibernate

J'ai recueilli des informations sur la méthode flush(), mais je ne sais pas vraiment quand l'utiliser et comment l'utiliser correctement. D'après ce que j'ai lu, je crois comprendre que le contenu du contexte de persistance sera synchronisé avec la base de données, c'est-à-dire qu'il s'agira d'émettre des instructions en suspens ou de rafraîchir les données des entités.

J'ai maintenant le scénario suivant avec deux entités A et B (dans une relation biunivoque, mais non appliquée ou modélisée par JPA). A a un PK composite, qui est défini manuellement, et a également un champ IDENTITY généré automatiquement. recordId . Ce site recordId doit être écrit dans l'entité B comme une clé étrangère à A . J'économise A et B en une seule transaction. Le problème est que la valeur générée automatiquement A.recordId n'est pas disponible au sein de la transaction, à moins que je ne fasse un appel explicite à la fonction em.flush() après avoir appelé em.persist() sur A . (Si j'ai un IDENTITY PK généré automatiquement, alors la valeur est directement mise à jour dans l'entité, mais ce n'est pas le cas ici).

Can em.flush() causer des dommages lors de son utilisation dans le cadre d'une transaction ?

162voto

Flavio Points 5369

Il est probable que les détails exacts de em.flush() dépendent de l'implémentation. En général, les fournisseurs JPA comme Hibernate peuvent mettre en cache les instructions SQL qu'ils sont censés envoyer à la base de données, souvent jusqu'à ce que vous validiez réellement la transaction. Par exemple, vous appelez em.persist() En effet, Hibernate se souvient qu'il doit effectuer un INSERT dans la base de données, mais n'exécute pas réellement l'instruction tant que vous n'avez pas validé la transaction. Je crois que cela est principalement fait pour des raisons de performance.

Dans certains cas, vous voulez quand même que les instructions SQL soient exécutées immédiatement ; généralement lorsque vous avez besoin du résultat de certains effets secondaires, comme une clé autogénérée, ou un déclencheur de base de données.

Quoi em.flush() consiste à vider le cache interne des instructions SQL et à les exécuter immédiatement dans la base de données.

En résumé, il n'y a pas d'inconvénient, mais vous pourriez avoir un impact (mineur) sur les performances, car vous remplacez les décisions du fournisseur JPA en ce qui concerne le meilleur moment pour envoyer des instructions SQL à la base de données.

1 votes

Ce qu'il a dit. Le comportement de em.flush() fait écho à java.io.Flushable.flush() où toutes les données mises en mémoire tampon sont envoyées vers la destination appropriée.

5 votes

Si flush() envoie des données à la base de données, que se passe-t-il si une exception est levée après cela ? Le gestionnaire d'entités annulera-t-il tout ? même les données écrites lors du premier flush ?

113 votes

Flush() envoie des instructions SQL à la base de données comme INSERT, UPDATE etc. Il n'enverra pas de COMMIT, donc si vous avez une exception après un flush(), vous pouvez toujours avoir un retour en arrière complet.

17voto

Rips Points 588

Vous trouverez ci-dessous un bon lien qui explique très clairement la chasse d'eau et la clarté.

Clair et net : les anti-modèles de cartographie O/R

2voto

En fait, em.flush() fait plus que simplement envoyer les commandes SQL mises en cache. Il essaie de synchroniser le contexte de persistance avec la base de données sous-jacente. Cela peut entraîner une forte consommation de temps sur vos processus si votre cache contient des collections à synchroniser.

Attention à son utilisation.

2voto

Gab Points 1979

em.flush() peut-il causer des dommages lorsqu'il est utilisé dans une transaction ?

Oui, il peut conserver des verrous dans la base de données pendant une durée plus longue que nécessaire.

En général, lorsque vous utilisez JPA, vous déléguez la gestion des transactions au conteneur (alias CMT - en utilisant l'annotation @Transactional sur les méthodes d'entreprise), ce qui signifie qu'une transaction est automatiquement lancée lors de l'entrée dans la méthode et commited / roll back à la fin. Si vous laissez l'EntityManager gérer la synchronisation de la base de données, l'exécution des instructions SQL ne sera déclenchée que juste avant le commit, ce qui entraînera des verrous de courte durée dans la base de données. Sinon, les opérations d'écriture effectuées manuellement peuvent conserver des verrous entre le vidage manuel et le commit automatique, ce qui peut être long en fonction du temps d'exécution restant de la méthode.

Il est à noter que certaines opérations déclenchent automatiquement un flush : l'exécution d'une requête native sur la même session (l'état de l'EM doit être flushé pour être accessible par la requête SQL), l'insertion d'entités à l'aide d'un identifiant généré nativement (généré par la base de données, l'instruction d'insertion doit donc être déclenchée pour que l'EM puisse récupérer l'identifiant généré et gérer correctement les relations).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X