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

Hibernate Java Discussion :

Hibernate et Servlet bonnes pratiques


Sujet :

Hibernate Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Avatar de natoine
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Décembre 2007
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Chercheur en informatique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 393
    Par défaut Hibernate et Servlet bonnes pratiques
    Voilà, je cherche une sorte de guide de bonnes pratiques pour faire de la persistence et des servlets (et des portlets aussi).

    Je ne sais pas si ça existe et je manque un peu d'expérience dans mon entourage pour répondre à toutes mes questions.

    Une première question : est-ce qu'il vaut mieux associer un emf à chaque servlet ou à chaque session ou à chaque action utilisateur qui nécessite de manipuler les données de la base ?

    J'utilise un pattern ou je fais des classes pour le modèle de données (les classes à persister).
    Et des classes pour gérer les requêtes (création, modifs, suppression, sélections). Est-ce qu'il vaut mieux que chacune des méthodes de ces classes (soit une méthode, une requête) ait sa propre transaction ou alors est-ce qu'il vaut mieux passer une transaction en paramétre de la méthode ?

    Je viendrai ajouter mes questions et réponse au fur et à mesure.
    Merci d'avance
    www.natoine.fr
    natoine.developpez.com
    Principalement du Java avec un soupçon de réseaux sociaux.

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Pour ta première question : assurément pas au niveau servlet !
    La session pourrait être envisagée mais je te le déconseille, ça risque de monopoliser des connexions alors qu'il n'y a plus personne côté client.
    L'idéal (pour moi) est à chaque groupe de demande (un request peu engendrer plusieurs requêtes de plusieurs "beans").

    Dans la mesure où ton pattern est proche (sinon identique) du pattern DAO, c'est au niveau de cette couche que la question se pose. Avec Hibernate, leur classe d'acquisition d'une session permet de gérer correctement le problème, elle ressemble à ceci
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    package com.obia.safe.hibernate.utils;
     
    import org.apache.log4j.Logger;
    import org.hibernate.HibernateException;
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    import com.obia.safe.hibernate.entity.interceptor.EntityInterceptor;
     
    public class HibernateUtils 
    {
        private static final SessionFactory sessionFactory;
        private static final Logger logger = Logger.getLogger(HibernateUtils.class);
     
        static 
        {
            try 
            {
                logger.debug("Création Session Factory Hibernate");
                sessionFactory = new Configuration().setInterceptor(new EntityInterceptor()).configure().buildSessionFactory();
            } 
            catch (HibernateException ex) 
            {
                logger.error("Erreur lors de la création de la Session Factory Hibernate : " + ex.getMessage());
                throw new RuntimeException("Problème de configuration : " + ex.getMessage(), ex);
            }
        }
     
        public static final ThreadLocal<Session> session = new ThreadLocal<Session>();
     
        /**
         *    Récupération de la session Hibernate
         */
        public static Session currentSession() throws HibernateException 
        {
            Session s = (Session) session.get();
     
            // Ouvre une nouvelle Session, si ce Thread n'en a aucune
            if (s == null) 
            {
                logger.debug("Acquisition d'une nouvelle Session Hibernate pour le Thread " + Thread.currentThread().hashCode());
                s = sessionFactory.openSession();
                session.set(s);
            }
     
            logger.debug("Récupération de la Session Hibernate " + s.hashCode() + " pour le Thread " + Thread.currentThread().hashCode());
            return s;
        }
     
        /**
         *    Fermeture de la session Hibernate
         */
        public static void closeSession() throws HibernateException 
        {
            Session s = (Session) session.get();
            if ( s == null ) return ;
     
            logger.debug("Fermeture de la Session Hibernate " + s.hashCode() + " pour le Thread " + Thread.currentThread().hashCode());
            session.set(null);
            s.close();
        }  
    }
    (là, j'utilise des interceptor, si tu n'en a pas, il suffit de retirer le "setInterceptor(...)" à la création de la factory).
    Dans les DAO, tu fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    HibernateUtils.currentSession().(etc...)
    Si tu as plusieurs DAO qui agissent, seul le premier fera l'acquisition, les autres utiliseront la session en cours.

    Pour l'aspect "transaction", c'est plus discutable.
    La DAO étant là pour centraliser une demande, la transaction pourrait se situer au-delà (surtout si plusieurs DAO sont mis en œuvre).
    Donc, pour ce problème, tu peux passer par le pattern Facade ou laisser ta méthode appelante dans la servlet gérer le commit ou rollback.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre éclairé
    Avatar de natoine
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Décembre 2007
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Chercheur en informatique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 393
    Par défaut
    Hum je comprends pas tout.
    Enfin, je suis pas sur.
    La DAO après avoir lu sur le web ce que c'était ça ressemble bien à ce que je fais.

    Du coup dans ces classes ou je m'occupe des requêtes, je devrai passer par la classe HibernatUtils pour gérer mes emf ?

    Je vais essayer voir si je trouve plus.
    Si tu as un exemple concret je suis preneur.

    Pour l'instant, mes classes de gestion de requêtes ressemblent à ça (un exemple) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
     
    public class CreateApplication 
    {
    private EntityManagerFactory emf = null ;
     
    	private EntityManagerFactory setEMF()
    	{
    		if(this.emf == null) emf = Persistence.createEntityManagerFactory("user");
    		return this.emf;
    	}
     
    	public boolean createApplication(String label, String description, Resource represents)
    	{
    		label = StringOp.deleteBlanks(label);
    		if(!StringOp.isNull(label))
    		{
    			if(description != null) description = StringOp.deleteBlanks(description);
    			Application _app = new Application();
    			_app.setDescription(description);
    			_app.setInscription(new Date());
    			_app.setLabel(label);
    			_app.setRepresents(represents);
    			EntityManagerFactory emf = this.setEMF();
    			EntityManager em = emf.createEntityManager();
    	        EntityTransaction tx = em.getTransaction();
    	        try{
    		        tx.begin();
    		        if(represents.getId() != null)
    	        	{
    		        	Resource _synchro_resource = em.find(Resource.class, represents.getId());
    					if(_synchro_resource != null) _app.setRepresents(_synchro_resource);
    	        	}
    		        em.persist(_app);
    		        tx.commit();
    		        //em.close();
    		        return true ;
    	        }
    	        catch(Exception e)
    	        {
    	        	tx.rollback();
    	        	System.out.println("[CreateApplication.createApplication] fails to create application"
    	        			+ " label : " + label 
    	        			+ " description : " + description
    	        			+ " cause : " + e.getMessage());
    	        	//em.close();
    	        	return false;
    	        }
    		}
    		else
    		{
    			System.out.println("[CreateApplication.createApplication] fails to create application"
            			+ " label : " + label 
            			+ " cause : this value is not correct" );
    		return false ;
    		}		
    	}
    }
    www.natoine.fr
    natoine.developpez.com
    Principalement du Java avec un soupçon de réseaux sociaux.

  4. #4
    Membre éclairé
    Avatar de natoine
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Décembre 2007
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Chercheur en informatique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 393
    Par défaut
    Ah et autre remarque, y a pas une solution équivalente sans être dépendant des packages hibernate ?

    Pour l'instant j'importe que des packages javax.persistence dans mes classes.
    www.natoine.fr
    natoine.developpez.com
    Principalement du Java avec un soupçon de réseaux sociaux.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2007
    Messages : 16
    Par défaut
    L'EMF te permet d'accèder à l'EM qui est l'objet dont tu va le plus te servir.

    Tu as beaucoup de choix pour obtenir une EMF (Persistence.fooStaticMethod(...), injection via @Resource en JEE5 ou @Inject en JEE6+CDI), voir même un EM directement (@Resource, @Inject ...).

    Dans tous les cas, l'EM est en fait stocké dans un ThreadLocal (voir la doc du JDK si tu connais pas). Il a donc un "scope" request dans le cas de servlet, vu que chaque requête à une servlet est traitée par un thread.

    En conséquence, si tu obtiens un EM dans ta servlet et dans ton DAO plus bas dans la pile, ce sera le même EM sur une requête donnée. Pratique non ?

    Quel que soit le nombre de traitements que tu veux faire lors d'une requête client j'imagine que tu veux qu'ils soient appliqués dans une seule transaction.

    J'imagine le pseudo code suivant (je laisse de coté l'obtention de l'EM et de tes DAO, ça dépends trop de ce que tu utilise ou que tu n'utilise pas .. j'ai aussi laissé de côté la gestion des erreurs) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
     
    class Servlet {
     
      EntityManager em;
     
      void doGet( ...... ) {
         em.begin();
     
         foo = fooDao.fetchSomeFoo();
         // ... do some work on foo
         fooDao.persist( foo );
     
         bar = barDao.fetchSomeBar();
         // ... do some work on bar
         barDao.persist( bar );
     
         em.commit();
      }
     
    }
     
    class FooDao {
     
       EntityManager em;
     
       Foo fetchSomeFoo() {
           return em.find( Foo.class, 1 );
       }
     
       Foo persist( Foo foo) {
           return em.persist( foo );
       }
     
    }
     
    // BarDao is the same
    En gros : tu mets la gestion de la transaction au plus haut, ici dans la servlet (ça pourrait aussi aller dans un Filter). Tu utilise l'EM dans tes DAOs comme si de rien était car l'EM est le même que celui utilisé pour ouvrir et fermer la transaction (ThreadLocal powah).

    Voila c'est l'idée générale que ce soit avec Hibernate ou un autre bidule de persistence qui gère des transactions. Par exemple en EJB/JDBC tu fais un peu pareil avec la UserTransaction (equivalent session ou EM) qui est elle aussi un ThreadLocal ... encore lui.

    J'espère que ça réponds à tes questions.

    PS: tu devrais laisser les exceptions remonter et mettre ton rollback dans un block finally plutot que de retourner du boolean ...

    PS2: avis très personnel : les DAOs c'est fait pour pouvoir changer d'outil de persistence mais les frameworks de persistence sont tellement couplants que ces DAOs perdent très rapidement leur interet, je penche plutôt pour l'idée de Repositories qui servent uniquement au queries (qui peuvent devenir compliquées si ton domaine l'est) et de manipuler directement l'EM dans tes services ... avis très personnel encore une fois

    /Paul

  6. #6
    Membre éclairé
    Avatar de natoine
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Décembre 2007
    Messages
    393
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Chercheur en informatique

    Informations forums :
    Inscription : Décembre 2007
    Messages : 393
    Par défaut
    Merci pour la réponse

    Alors mes retours, ça génére plus de questions que de réponses de mon côté ^^

    * Je veux bien en savoir plus sur les Repositories. J'ai lu ça du coup mais je sais pas si c'est un bon exemple : http://debasishg.blogspot.com/2007/0...rm-backed.html
    * Si je mets mon rollback dans un finally, il sera toujours exécuté. Du coup c'est comme si je faisais aucune transaction non ?
    * Est-ce que j'ai bien compris, en gros je mets un EMF en attribut à chaque servlet et dans mes doGet ou doPost je récupére un EM et je fais ma sauce avec (le ThreadLocal est créé que lors d'une requête http à ma servlet non ?). Ou est-ce que je mets cet EM en attribut aussi ?
    * Il faut pas le fermer l'EM quand on en a fini avec ? EM.close() à la fin de doGet et de doPost ou dans la méthode destroy de ma servlet ?
    www.natoine.fr
    natoine.developpez.com
    Principalement du Java avec un soupçon de réseaux sociaux.

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

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par eskatos Voir le message
    PS: tu devrais laisser les exceptions remonter et mettre ton rollback dans un block finally plutot que de retourner du boolean ...
    Dans le bloc Exception, pas finally puisqu'on y passe systématiquement.
    Citation Envoyé par eskatos Voir le message
    PS2: avis très personnel : les DAOs c'est fait pour pouvoir changer d'outil de persistence mais les frameworks de persistence sont tellement couplants que ces DAOs perdent très rapidement leur interet, je penche plutôt pour l'idée de Repositories qui servent uniquement au queries (qui peuvent devenir compliquées si ton domaine l'est) et de manipuler directement l'EM dans tes services ... avis très personnel encore une fois
    Si on veut s'affranchir des outils de persistance, le mieux est d'utiliser JPA.
    La plupart des ORM (Hibernate, TopLink, ...) sont les implémentations de JPA, on perd certaines fonctionnalités propriétaires mais on gagne en liberté de choix de l'implémentation (JPA).
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

Discussions similaires

  1. Bonnes pratiques de protections individuelles
    Par Community Management dans le forum Sécurité
    Réponses: 23
    Dernier message: 11/06/2024, 11h23
  2. Réponses: 13
    Dernier message: 13/03/2009, 09h38
  3. [session hibernate]bonnes pratiques
    Par centoo dans le forum Hibernate
    Réponses: 6
    Dernier message: 06/05/2008, 16h25
  4. [FOREIGN K] Valeur de champ = nom de table. Bonne pratique ?
    Par Seb des Monts dans le forum Langage SQL
    Réponses: 9
    Dernier message: 17/05/2005, 10h56

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