0 votes

Profiter du chargement paresseux de Hibernate?

J'ai un objet de domaine qui a un attribut qui est une collection contenant un autre objet de domaine. Cela est réalisé en utilisant un mappage Hibernate (qui effectue finalement une jointure sur une autre table). Par défaut, Hibernate semble instancier paresseusement cette collection. Cela s'avère être une bonne chose car, en fonction de ce que j'ai besoin d'afficher, je n'ai pas toujours besoin que la collection soit chargée.

Mon problème est le suivant : lorsque j'écris mes requêtes Hibernate (dans mes DAO), j'utilise ce qui suit pour ouvrir / fermer une Session :

Session session = getSessionFactory().openSession();
//query goes here using the session var
session.close();

Le problème est le suivant : lorsque Hibernate finit par charger paresseusement ma collection, la Session a été depuis longtemps fermée ! Comment puis-je contourner cela ? Je suppose que je dois fermer la session comme je le fais actuellement...

Voici l'erreur que j'obtiens :

SEVERE: failed to lazily initialize a collection of ...

4voto

skaffman Points 197885

Si cela se produit dans une application Web, la solution facile est d'utiliser un OpenSessionInViewInterceptor ou un OpenSessionInViewFilter. Ces derniers retardent la fermeture de la session jusqu'à ce que la requête soit entièrement terminée, ce qui vous permet de naviguer dans les associations paresseuses lors du rendu de la vue.

Une solution plus générale consiste à réécrire vos requêtes pour spécifier explicitement quelles associations doivent être récupérées dès le départ. Cela vous permet de conserver les associations paresseuses par défaut, tout en répondant aux cas spéciaux où vous souhaitez les récupérer de manière anticipée. Voir la description des "fetch joins" dans la documentation de Hibernate.

Un "fetch" join permet d'initialiser les associations ou les collections de valeurs avec leurs objets parents en une seule requête. Cela est particulièrement utile dans le cas d'une collection. Cela remplace effectivement les déclarations de jointures externes et paresseuses du fichier de mappage pour les associations et collections.

1voto

Péter Török Points 72981

Je comprends que vous ouvrez et fermez la session pour chaque opération DAO. Vous pourriez plutôt utiliser une même session pour tous les DAO, ouverte à un moment donné pendant l'initialisation et fermée à l'arrêt. Notez que le Référence Hibernate mentionne "session par opération" comme un anti-pattern :

"Ne pas utiliser l'anti-pattern session-par-opération : ne pas ouvrir et fermer une Session pour chaque simple appel à la base de données dans un seul thread."

En bref, une session devrait contenir une unité de travail. Il peut s'agir d'une simple requête utilisateur (comprenant éventuellement plusieurs requêtes), ou d'une conversation plus longue (comprenant plusieurs écrans avec leurs propres (groupes de) requêtes). Dans ce dernier cas, il est important de ne pas conserver la session (= transaction) ouverte pendant de longues périodes de réflexion de l'utilisateur, mais cela ne semble pas être votre cas selon moi.

Si vous fermez la session, votre objet de domaine devient détaché. Vous pourriez ouvrir une nouvelle session, lier votre objet à celle-ci puis charger la collection, mais cela me semble assez compliqué.

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