IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement Web en Java Discussion :

La gestion de la session de persistence dans une application web


Sujet :

Développement Web en Java

  1. #1
    Expert éminent
    Avatar de djo.mos
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    4 666
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 4 666
    Points : 7 679
    Points
    7 679
    Par défaut La gestion de la session de persistence dans une application web
    Bonjour.
    Suite à d'âpres combats et nuits blanches, et de solutions trafiquotées, je lance cette discussion pour vous demander vos avis et vos retours d'expériences sur le sujet.
    Il s'agit de l'utilisation d'Hibernate (ou un autre framework de persistence) dans le contexte d'une application web.
    Le problème se résume au mot "Lazy Fetching Exception", je ne sais pas pour vous, mais en ce qui me concerne, ça m'a pourri la vie au départ (et même quelques fois maintenant). Ce problème provient de deux causes (en général) :
    • lors du rendu des views (après les appels aux DAOs et la fin des transactions du framework de persistence.
    • lors des prochaines requêtes (suite à la fermeture et à la réouverture de la session du framework de persistence), lors de l'accès aux objets détachés.
    A travers plusieurs projets, j'ai utilisé plusieures des solutions suivantes :
    • mettre toutes les associations au mode EAGER : Je sais, c'est moche et stupide, mais ça résout tout ! Assurez vous cependant, je le fais plus, c'etait à l'époque de mes premiers projets Struts-Hibernate.
    • Rafraichir systématiquement les DTOs avant de leur accéder. j' ajoute une méthode refresh(id) dans mes DAOs qui retrouve mon bean via son id et le sort ainsi de l'état detached. Solution très lourde à mettre en oeuvre, rallonge le code, augmente le traffic de/vers la BD. Ceci résout le second problème.
    • Déléger l'ouverture et fermeture des transactions à une couche supérieure, comme à un filtre par exemple. pas joli comme manip !
    • etc..
    • Ouvrir une session de persistence par utilisateur et la stocker dans sa session (web, coté serveur) : J'adore cette solution ! plus de refresh, plus de lazy fetch exceptions, etc. MAIS, pour l'utilisation de la RAM et d'espace session, bonjour les dégats ! C'est la solution que j'utilises actuellement.
    Bref, je souhaitais vous demander votre avis sur la question.

    P.S. : je parle d'un environnement web dans un Servlet Container uniquement, comme Tomcat par exemple. Je précise ceci pour pas que l'on me propose d'utiliser les managed sessions des EJB3 et compagnie.

    En attendnt vos réponses, merci d'avance.

  2. #2
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Et bien personnellement je développe une application WEB avec un serveur TOMCAT (pour les tests) avec une couche de persistence hibernate et je n'ai jamais été confronté à un problème lié au lazy loading...
    Plutôt à des problèmes de mise à jour avec un message du type "il y a déjà un objet en session avec le même id" (lié à des contrôles avec "oublie" d'evict)
    Bref, j'utilise :
    - une couche ActionForm
    - une couche DispatchAction
    - une couche service qui permet de centraliser les opérations DB (métier)
    - une couche POJO (hibernate)
    - une couche présentation JSP (avec Struts-Layout)

    Pour ne pas être confronté au problème de lazy loading, mes contrôleurs s'arrangent pour faire des accès aux sous-objets dans la mesure où ils sont utilisés par la couche de présentation. Ainsi, même si quelqu'un (par la suite) modifiait le paramétrage d'hibernate, ça continuera de fonctionner.
    C'est d'ailleurs un point critique de cette techno, tu places judicieusement un lazy="false", tu traites les données dans la page, et un jour, quelqu'un se dit "je vais optimiser tout ça", et là,

    J'ajoute que mes contrôleurs ont un point d'entrée commun qui s'occupe (entre autre) de récupérer une Session (hibernate) et de la libérer. La couche Service ne s'occupe jamais de ça, elle utilise un context qu'on lui passe (pour la gestion des transactions multi-services, ça aide... )

    C'est sûr, ma façon de faire rajoute du code dans les contrôleurs (très peu en fait) et ajoute un lien fort entre la page et le contrôleur, mais au moins, ça colle.

    A+
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre confirmé
    Avatar de grishka
    Inscrit en
    Janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Janvier 2003
    Messages : 285
    Points : 499
    Points
    499
    Par défaut
    je pense que c'est plus un problème de conception qu'un problème technique

    j'ai été très "extremiste" et j'ai laissé le mode lazy par défaut pour toutes les associations dans la définition du mapping. La couche d'accès aux données est censée fournir tous les objets nécessaires à la présentation. Donc j'ai utilisé systématiquement des requêtes HQL et des jointures rapportées (fetch join). La portée de la session Hibernate est normalement restreinte à la couche Dao. Par contre il est possible de démarquer les transactions applicatives au niveau de la couche service ou action (donc il est possible de rapporter plus d'objets que ce que retourne la couche dao tant que l'on reste dans cette démarcation, ce qui a mon sens est mal ).
    autre problème : l'objet détaché issu de la présentation ne contient pas un l'objet associé lors de l'enregistrement des modifs (ou lors d'un contrôle) : généralement un saveOrUpdate suffit pour resynchroniser l'objet avec la base.

    pour le problème "il y a déjà un objet en session avec le même id", j'ai utilisé session.merge() de mémoire
    "Les gens normaux croient que si ca marche, c'est qu'il n'y a rien à reparer. Les ingénieurs croient que si ca marche, c'est que ca ne fait pas encore assez de choses."
    --Scott Adams

  4. #4
    Membre expérimenté
    Avatar de azerr
    Homme Profil pro
    Ingénieur Etude JEE/Eclipse RCP
    Inscrit en
    Avril 2006
    Messages
    942
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Etude JEE/Eclipse RCP
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2006
    Messages : 942
    Points : 1 464
    Points
    1 464
    Par défaut
    Bonjour,
    merci pour ce post qui est un sujet très intéressant et qui paraît au début simple à mettre en place. Je n'ai pas la science infuse, mais après de multiple lecture et d'essai que j'ai pu faire l'architecture que j'utilise est la suivante:

    • une couche DAO : qui permet de gerer les acces aux donnees. Cette couche retourne les Bean persistent d'Hibernate sans effectuer un detachemenet de l'objet.
    • une couche Service : qui permet de gérer le métier de l'application.
      Les services font appels aux DAO. Ce sont eux qui gèrent les transactions, ouverture/fermeture des connections. Les ActionStruts qui font appel à ces services utilisent des interfaces services et non leur implémentation. Ce mecanisme permet d'etre tres evolutif. En effet si le jour ou vous decidez de changer le mode d'acces aux donnees (ex passer d'une base de donnees SGBD a une base XML, ou a un appel a un Web Service), les Action Struts ne seront pas impactes. Seul les impelementatons des Services devront etre developes. Avec Spring, l'implementation du service est defini dans son fichier de config qui permet dans ce cas de jouer le role de factory. Pour modifier l'implementation du service il suffit juste de modifier le fichier spring.


    Cette technique permet de faire des Mock Object (classe bouchon). Souvent un developpeur a besoin d'un service qui n'est pas encore developpe pour l'appeler dans son Action Struts. Il suffit de definir l'interface service. Le developpeur implemente ce service qui retourne des donnees coder en dur (sans acceder à la base) et definit dans le fichier de config Spring d'utiliser cette implemntation. Il ne pollue pas le projet avec son implementation du service.

    Une couche service definit la logique de l'application, mais aussi celle de l'entreprise. En effet ces service pourrait etre appele dans une autre application (comme une application Swing). Donc la règle que je me suis fixé et de n'utiliser aucun contexte particulier (HTTP request,Http session) dans les services. De plus ca n'est pas a la couche qui appele ces services de gerer mes transactions,...

    Sur le site Hibernate, il existe plusieurs facon de gerer la session Hibernate. ce que j'ai retenu :

    • Open In View : qui signifie que la session est ouverte dans la couche Vue presentation (pour pouvoir utiliser le mode lazy). Ceci necessite de developper un filter qui ouvre une session au debut du filtre et qui la ferme a la fin (une fois que la JSP a fini d'etre parse). Cette solution peut paraitre au debut tres seduisante, car on peut appeler en mode lazy des lists dans les JSP.
      Mais je ne l'aime pas car :

      1. le mode lazy je ne l'utilise plus, car meme si il parait tres seduisant, il peut plomber les performances tres rapidement (un item d'une liste appele une liste qui appele un autre liste,...). Et meme si on se dit "OK je connais ce probleme, je vais faire attention, je vais l'utiliser juste pour une petite liste", une application evolue et ses donnees aussi et on peut rapidement plomber les performances. Apres evolution, cette petite liste peut faire reference a d'autre liste et c'est la ou ca devient un cauchemard.
      2. la gestion d'erreur est impossible a effectuer. En effet uen requete plante, la page ne pourra pas s'afficher, alors que souvent on souhaite afficher un message d'avertissement ou d'erreur avec le formulaire de la page.
      3. On cree un fort couplage avec Hibernate. Le jour on l'on souhaite change de mode d'accès, il faut revoir toute l'architecture de l'application.

    • ThreadLocal : (c'est celle que je prefere) la session hibernate est mise dans une ThreadLocale. Si vous ne connaissez pas cette objet, je vous conseille de l'etudier. Il n'est vraiment pas complique, et il permet de reglmer beaucoup de problemes. Une ThreadLocal est une Thread qui s'attache a la Thread courante. Par exemple, ce que je fait souvent, c'est de mettre dans une ThredLocal mon objet User (qui est aussi stocke dans la session) a l'aide de mon RequestProcessor de Struts. L'interet de ce mecanisme est de pouvoir recuperer mon objet User sans avoir le contexte Session.

      Vous pouver recuperer le User dans un getter d'une classe JAVA qui n'a pas le contexte Session.

      Pour Hibernate c'est pareil. On stocke la session hibernate dans une ThreadLocal (au lieu de la mettre dans une Session utilisateur). Il y a de nombreux exemples sur le WEB de classe utilitaire Hibernate Session.


    La couche service recupere les Bean des DAO (implemente en Hibernate).
    Les DAO n'ont aucun metier dans leur code! Elle font juste les acces aux donnees. Ce sont les services qui gere le metier. Les services retournent les DTO et pas les Bean. Cette couche joue le role d'assemblage des DTO a partir de plusieurs Bean.

    Ca c'est un sujet polémique, car souvent on me dit "pourquoi ne pas utiliser les Bean directement?". Si on veut utiliser les Bean directement ceci signifie que :

    1. il faut absolument detacher l'objet de la session Hibernate lorsque le service retourne le Bean a la couche Action.
    2. On cree un fort couplage avec la base de donnees. Meme si Hibernate est tres puissant pour creer un graphe d'objet. Le jour ou la structure de la base de donnees change, la structure des Bean change aussi et du coup les Action Struts sont aussi impactes. Si le Service assemble les DTO a partir des Beans, seul cette couche sera impactée.


    Avec cette architecture en service, l'ouverture de la session s'effectue au debut de l'appel de la methode du service et en fin de l'appel. C'est sur ce sujet que Spring (et je pense que EJB3 fait la meme chose) intervient et dont je ne plus m'en passer.

    En effet souvent, on creer un service qui :
    * creer un utilisateur createUser
    * creer l'association roles/utilisateur createRoles.

    Et puis on souhaite creer un service qui fait appel aux 2, mais dans la même transaction. Si on code l'ouverture/fermeture des sessions au debut et fin de méthode, on ne peut gerer ce cas. Pour faire ceci on doit changer des methodes createUser, createRoles en leur passant la session en parametres.
    Il ya donc deux methodes pour chacun des services :

    * createUser(Session session) => qui cree un utilisateur mais qui ne commit pas la transaction.
    * createUser() => qui fait appel a la methode createUser(Session session) et qui commite la session.

    En suite on peut faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    createUserRoles() {
    Session session = ...
    createUser(session)
    createRoles (session)
    // commit de la session
    }
    Mais ca peut devenir horrible si on doit faire ca pour d'autres services.
    Avec Spring, on ne se soucie pas de l'ouverture/fermeture de la connection.
    En effet Spring est base sur le de l'AOP (Programmation par Aspect) qui permet de definir des regles sur les appeles des methodes.

    Pour simplifier on definit la regles au debut de l'appel des methodes create*
    on ouvre une session en transation et a la fin de la methode ou commit ou rollback.

    Je ne vais pas m'etendre sur le sujet, mais j'ai tente d'expliquer tout ca sur http://gestcv.sourceforge.net/fr/arc...re/spring.html

    Etant donne que ce post concerne l'architecture d'une application J2EE, je me permets aussi de vous parler rapidement d'Akrogen http://akrogen.sourceforge.net/fr/ qui est un plugin Eclipse de generation de code qui permet de decrire ses Wizards page en XML/XUL & Javascript.

    L'inetret d'Akrogen est de pouvoir creer des templates et des Wizard Eclispe
    pour sa propre architecture. Car souvent les generateurs de code ont des Wizards Eclipse code en JAVA mais qui nbe sont pas parametrables. Avec Akrogen vous ecrivez votre Wizard page en XML/XUL et Javascript (por gerer la logique du Wizard page).

    J'ai commence a creer un catalogue de template pour Struts 1.x (c'est tes basique pour l'instant) http://akrogen.sourceforge.net/fr/st.../struts1x.html
    Si vous ete sinteresses pour m'aider a concevoir d'autres catalogues (pour Hibernate, struts 2.x,...) n'hesitez pas à me contacter.

    Voila j'espere que j'ai ete clair dans mes explications, et n'hesitez surtout pas a me critiquer.

    Angelo

  5. #5
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    J'aime bien l'utilisation du filtre pour la centralisation de la libération...
    J'utilise également ThreadLocal mais il faut bien reconnaitre qu'il y a des limites vite atteintes (surtout avec struts) vu que chaque contrôleur tourne dans son propre thread.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre expérimenté
    Avatar de azerr
    Homme Profil pro
    Ingénieur Etude JEE/Eclipse RCP
    Inscrit en
    Avril 2006
    Messages
    942
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Etude JEE/Eclipse RCP
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2006
    Messages : 942
    Points : 1 464
    Points
    1 464
    Par défaut
    Bonjour Obretin

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    J'aime bien l'utilisation du filtre pour la centralisation de la libération...
    Comme je disais dans mon post, en faisant ca tu creer un fort couplage Hibernate dans ton Application Struts.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    J'utilise également ThreadLocal mais il faut bien reconnaitre qu'il y a des limites vite atteintes (surtout avec struts) vu que chaque contrôleur tourne dans son propre thread.
    Je suis desole mais je ne comprends pas trop ce que tu veux dire. Dans mon projet gestcv http://gestcv.sourceforge.net/fr/architecture.html, je mets mon objet User stocké en session dans une ThreadLocal dans la methode process du RequestProcessor. Le RequestProcessor etant le premier appele avant les Actions, je suis sur que mon objet user est mis a jour correctement dans la ThreadLocal.

    Chaque appel d'une url sur le serveur creer une tache ou recupere une tache
    du pooling de tache. Le Requestprocessor met a jour cet objet user en premier et les actiosn peuvent ensuite bénéficier de l'objet user mis dans la ThreadLocal.

    mais peut etre que je n'ai pas bien compris ton probleme?

    Angelo

  7. #7
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Tu entends quoi par couplage fort dans ce cas de figure ?
    (je n'utilise ce point que pour libérer les ressources)

    Pour l'autre point, à vrai dire, je ne connais pas d'avance si j'aurai besoin d'une liaison avec la DB ou pas et donc, je demande une session à la première demande. Le problème, c'est qu'avec le ThreadLocal, on est ici lié au thread du contrôleur et donc, dans un même "request", on peut avoir plus d'une session (Heureusement, la structure de l'application fait que ça ne gène pas, mais c'est tout de même bête de fermer et reouvrir une session dans le même request)

    Dans tous les cas, je vais jeter un oeil sur le RequestProcessor, ça parait bon...

    A+
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  8. #8
    Membre expérimenté
    Avatar de azerr
    Homme Profil pro
    Ingénieur Etude JEE/Eclipse RCP
    Inscrit en
    Avril 2006
    Messages
    942
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Etude JEE/Eclipse RCP
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2006
    Messages : 942
    Points : 1 464
    Points
    1 464
    Par défaut
    Ce que je veux dire c'est que ton application ne peut pas tourner sans ce filtre.
    Toutes autres applications qui voudraient utiliser tes services ou DAO seront oblige de mettre en place ce filtre. Imagine que tu veuilles utiliser tes services dans une autre application (SWING) par exemple, il faudra developper une classe qui permette de simuler ce filtre.

    Ok j'ai compris ton probleme, dans ton ca ci tu ne peux pas utiliser de Threadlocale.

    Angelo

  9. #9
    Membre confirmé
    Avatar de grishka
    Inscrit en
    Janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Janvier 2003
    Messages : 285
    Points : 499
    Points
    499
    Par défaut
    l'ouverture/fermeture de session hibernate via un filtre JEE ou le requestprocessor de Struts résoud le problème de "lazy initialization", mais cette solution n'est valable que si la couche web tier et la couche business sont sur le même serveur. La session hibernate ne peut pas être propagée lors de l'invocation de méthode via RMI ou EJB session. cest problématique pour la montée en charge (impossible d'utiliser plusieurs serveurs pour la couche business) et donc plutot adapté aux petites applications.

    Normalement la couche web tier ne devrait pas déclencher les accès à la base de donnée, car ca casse le modèle en couche. Les méthodes dao doivent donc retourner la grappe d'objet nécessaire à la couche service ou web tier (d'où un problème plutot orienté conception).
    D'ailleurs l'exception "lazy initialization" remontée par hibernate est de type Runtime Exception, ce qui correspond à une erreur de programmation (le code n'est pas en phase avec la spécification)
    "Les gens normaux croient que si ca marche, c'est qu'il n'y a rien à reparer. Les ingénieurs croient que si ca marche, c'est que ca ne fait pas encore assez de choses."
    --Scott Adams

  10. #10
    Expert éminent
    Avatar de djo.mos
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    4 666
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 4 666
    Points : 7 679
    Points
    7 679
    Par défaut
    Citation Envoyé par Grégory Picavet
    D'ailleurs l'exception "lazy initialization" remontée par hibernate est de type Runtime Exception, ce qui correspond à une erreur de programmation (le code n'est pas en phase avec la spécification)
    Là je dois dire que je ne suis pas du tout d'accord !

    Considérons le scénario suivant :
    - Le controlleur demande à la couche DAO où Service un DTO X qui contient une association avec un autre DTO Y.
    - La DAO ouvre une transaction, récupère X, ferme la transaction et le retourne au contôleur.
    - Le contrôleur essaie d'accéder à X.Y
    ==> Lazy initialization Exception !

    Dire que c'est une erreur de Design ou encore une limitation technique du middle-tier, OK ! mais une erreur de programmation, je n'en suis pas sûr !

    Comme solutions trafiquotées, on peut effectivement faire un accès vide à toutes les entités en relation avec X avant la fermeture de la transaction, mais ce n'est pas concevable dans une application qui traite de données imposantes.

    Merci infiniment à tout le monde, j'apprends énormément de vos posts !

  11. #11
    Membre confirmé
    Avatar de grishka
    Inscrit en
    Janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Janvier 2003
    Messages : 285
    Points : 499
    Points
    499
    Par défaut
    le fait que la couche web tiers essaye de récupérer plus d'objet que ce qui a été spécifié pour la méthode DAO est pour moi une erreur de programmation du même style que NullPointerException, c'est à dire une erreur qu'on aurait pu prévoir en regard des spec. Alors bien sur il faut être clair dans la documentation des méthodes dao que l'on fournit à la personne en charge de la couche web tiers.
    "Les gens normaux croient que si ca marche, c'est qu'il n'y a rien à reparer. Les ingénieurs croient que si ca marche, c'est que ca ne fait pas encore assez de choses."
    --Scott Adams

  12. #12
    Membre habitué
    Inscrit en
    Décembre 2002
    Messages
    186
    Détails du profil
    Informations forums :
    Inscription : Décembre 2002
    Messages : 186
    Points : 130
    Points
    130
    Par défaut
    et utiliser des VO construits dans la couche service à partir des données nécessaires d'un ou plusieur bean?
    Ok c'est lourd si on a un modele objet assez riche, en particulier lorsqu'on désire remonter un graphe d'objet, mais je trouve que ca reste éléguant, surtout dans une architecture de type SOA ou le client peut être une appli web, un webservice, un client lourd, ...
    ... mais on évite des pb de lazy loading et on ne lie pas la session orm à l'ensemble des couches.

    Il faut aussi se rendre à l'évidence, si une couche de mapping apporte pas mal de fonctionnalités, elle apporte également son lot de questions et de problèmes.
    Après il faut trouver un bon compromis, je pense que ici chacun a sa facon de voir les choses, mais LA solution miracle et universelle n'existe pas. Il y a toujours des avantages / inconvénients, le + dur est certainement de les connaitres pour chaque solutions puis de justifier son choix final.

    Il faut réfléchir en terme de maintenance, de lisibilité du code, compréhention de l'architecture par les développeurs, charge du projet, réel besoin de performances, de mise à l'échelle, etc...

  13. #13
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 310
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 310
    Points : 9 522
    Points
    9 522
    Billets dans le blog
    1
    Par défaut
    Je suis bien d'accord, la solution miracle n'existe pas.
    Le problème, quand même, c'est qu'à la base le lazy loading a été imaginé pour règler des problèmes de performances et que finalement, le modèle en couche va un peu contre.
    Comme le dit Grégory Picavet, il faudrait passer par des grappes d'objets, le problème, c'est qu'en fonction de l'ihm, on utilise (ou pas) certaines données et donc, ça obligerait à faire plusieurs types de grappes (un peu lourd)...
    D'ailleurs, dans ce contexte, où centraliser les contrôles ? au niveau des pojos (bof, trop limité) ? par les classes métier (ça parait mieux, mais ça oblige à certains artifices pour des objets récurants (adresses, personnes, utilisateurs, etc...)).
    Vous faites comments vous ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  14. #14
    Membre confirmé
    Avatar de grishka
    Inscrit en
    Janvier 2003
    Messages
    285
    Détails du profil
    Informations forums :
    Inscription : Janvier 2003
    Messages : 285
    Points : 499
    Points
    499
    Par défaut
    c'est clair la solution doit être adaptée à son besoin.
    En fait le choix de ne pas utiliser la session de persistance dans la couche web tiers, c'est plus pour permettre la séparation physique des couches (ou alors il faudrait créer des classes persistantes distante, ejb-like, le délire quoi). Maintenant sur de petites applications style intranet, le Lazy Loading permet sans doute plus de flexibilité et de productivité si on n'est pas trop regardant sur les performances, ou qu'on souhaite prototyper une partie de l'appli. Car il y a un risque de plomber les performances par exemple en accédant aux collections via le graphe d'objet (N+1 select). On peut certes forcer lazy=false dans le mapping mais au risque de plomber les performances dans d'autres parties. Ca devient vite un casse tête et du coup il faut écrire des requêtes spécifiques en HQL.
    "Les gens normaux croient que si ca marche, c'est qu'il n'y a rien à reparer. Les ingénieurs croient que si ca marche, c'est que ca ne fait pas encore assez de choses."
    --Scott Adams

  15. #15
    Membre habitué
    Inscrit en
    Décembre 2002
    Messages
    186
    Détails du profil
    Informations forums :
    Inscription : Décembre 2002
    Messages : 186
    Points : 130
    Points
    130
    Par défaut
    En fait le choix de ne pas utiliser la session de persistance dans la couche web tiers, c'est plus pour permettre la séparation physique des couches
    et pour des projets de petite envergure, cette "absolue" séparation des couches, cette imperméabilité totale conduit parfois à des complications qui ne sont vraiment pas nécessaires. C'est sur, c'est propre, on peut interchanger l'implémentation, mais honetement, à part respecter à la lettre certains design que des gourous j2ee nous servent sans connaitre notre cible, ca apporte trop peu.

    [edit] Hors sujet...

    J'ai eu l'occasion de conduire un projet de moyenne taille, en y ajoutant un but pédagogique, donc en suivant scrupuleusement les "best practice", et bien quand on regarde le temps passé et la complexité pour des non initiés, on ne s'y retrouve vraiment pas... et le patron a le droit de faire la tronche.

    Aujourd'hui je travail sur un gros projet (+20.000j), et là certaines décisions architecturale, technologiques et techniques sont pleinement justifiées. On encapsule tout ca dans un socle technique pour donner un cadre d'utilisation à cette foultitude de framework + codification + intégration continue, ... et la ca vaut le coup... mais forcemement, ca a un cout (énorme)!

    Se pose à mon avis 2 problèmes majeurs:
    - la sur-compétence des développeurs (maitriser à la fois le model relationnel et maitriser le fonctionnement des orm) nécessaire.
    - du coup on s'interdit le recours à des "développeurs fonctionnels", et on a plus de difficulté à répartir les taches dans l'équipe



    Ce qui pourait être interessant, ce serait de recensser toutes les questions techniques à prendre en considération dans n'importe quel projet voulant utiliser un orm.
    Allez, hop un exemple avec un sujet chaud: les collections avec hibernate (pour être populaire)
    implémenter equals et hashcode

    La liste est longue.

    [/edit]

    Sinon, je peux conseille souvent de regarder appfuse pour se faire une idée

  16. #16
    Expert éminent
    Avatar de djo.mos
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    4 666
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 4 666
    Points : 7 679
    Points
    7 679
    Par défaut
    Bonjour.
    Je voulais juste vous informer de la sortie d'une nouveau seam-like du coté d'Apache Software Foundation : Orchestra.
    Je n'ai pas eu le temps de le tester (je suis enfoui jusqu'au cou dans un projet et faire marche arrière pour inclure un tel framework est du suicide ), mais j'adore le principe.

    Le but de ce framework est justement d'éviter le maudit Lazy Fetch Exception et compagnie dans une application multi-tiers (web surtout), en injectant l'EntityManager (pour une implémentation JPA comme Hibernate ou TopLink par exemple) dans les DAOs.

  17. #17
    Membre expérimenté
    Avatar de azerr
    Homme Profil pro
    Ingénieur Etude JEE/Eclipse RCP
    Inscrit en
    Avril 2006
    Messages
    942
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Drôme (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur Etude JEE/Eclipse RCP
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2006
    Messages : 942
    Points : 1 464
    Points
    1 464
    Par défaut
    Bonjour Modjo,
    merci pour l'information. Orchestra est apperement basé sur des descripteurs Spring, ca c'est un point positif. Va falloir trouver un moment pour étudier ce framework (mais quand est ce que je vais dormir? )

    Angelo

  18. #18
    Futur Membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 6
    Points : 6
    Points
    6
    Par défaut
    Bonjour à tous,

    Je suis confronté à un probleme de lazy loading. j'ai un découpage tres simple : objet métier, DAO, JSP/Servlet. Mes objets sont chargés dans mes DAO, et mes JSP affichent leur contenu

    J'ai lu attentivement les échanges de ce posts, mais je dois avouer que les solutions proposées par chacun me paraisse compliquées par rapport à mon souci et mes compétences... et je me dis qu'il y a peut etre une solution plus simple ?

    Je vous explique... Pour isoler le probleme, on va dire que j'ai trois classes
    - Cheval avec comme propriétés : Long id,String sexe, String nom, int age, Etable etableRatachee, List listeJockeys.
    - Etable: Long id, int numeroEmplacement
    - Jockey : Long id, String nom, String prenom...

    Un cheval est rataché à une seule étable. Il peut etre monté par une liste de Jockeys.

    Lorsque je veux faire un monCheval.getEtable(), j'ai une exception de lazy initialisation...

    Question 1 : J'ai cru comprendre qu'il était possible d'initialiser une collection de la sorte : Hibernate.initialize(nomDeLaCollection).
    Donc je présume que si je fais un :

    Hibernate.initialize(monCheval.getListeJockeys());

    dans la session de mon DAO, que je ferme ma session dans mon DAO, lorsque j'accederais à monCheval.getListeJockeys(), je n'aurais pas de probleme de lazyinitialisationexception. Est ce bien cela ?

    Je n'ai pas essayé pour la collection de ListeJockeys, car pour le moment je n'en suis pas la car je suis bloqué dans la seconde question...

    Question 2 : La où je suis coincé pour le moment, c'est sur
    monCheval.getEtableRatachee();

    J'ai une lazyinitialisationexception... Visiblement ca ne charge pas l objet etableRattachee si je fais un
    Hibernate.initialize(monCheval.getEtableRattachee());

    (Dans mon mapping je suis par défaut en lazy=true).
    Y a t il un moyen "simple" de charger cet objet dans mon DAO tant que ma session est ouverte, afin de pouvoir l'utiliser dans ma couche de présentation ?

    Question 3 : dans mon dao qui me permettra de récupérer de mes chevaux, et leur graphes associés, j'aurais un code similaire à celui la :

    List lChevaux = (List) s.createQuery("from Cheval where sexe='f'").list();

    Donc j'aurais une liste de cheval en retour. Mais la aussi j'aurais le probleme des etablesRatachees non chargees. Comment faire pour forcer leur chargement ?

    Quelqu'un peut il m'aider ?

Discussions similaires

  1. [MySQL] Gestion des données d'un utilisateur dans une application
    Par Boujoute dans le forum PHP & Base de données
    Réponses: 4
    Dernier message: 05/06/2012, 15h48
  2. Problème de gestion de suppression dans une application web dynamic data
    Par mo5andes dans le forum Développement Web avec .NET
    Réponses: 4
    Dernier message: 21/06/2010, 11h35
  3. XML/XSL et gestion des fichiers dans une application Web
    Par fatenatwork dans le forum XML/XSL et SOAP
    Réponses: 1
    Dernier message: 01/02/2008, 15h09
  4. Persistence dans une application desktop
    Par jproto dans le forum NetBeans
    Réponses: 4
    Dernier message: 04/07/2006, 15h01
  5. Réponses: 2
    Dernier message: 24/01/2006, 10h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo