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

Spring Java Discussion :

Ouverture d'une nouvelle session à chaque appel d'une méthode transactionnelle


Sujet :

Spring Java

  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut Ouverture d'une nouvelle session à chaque appel d'une méthode transactionnelle
    j'ai moi aussi mis en place la gestion des transactions avec les annotations et quelque chose m'intrigue.

    j'ai une classe service, de mémoire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    @Transactional
    ServiceImpl implements Service {
       public Set getFiles(){...};
       public Set getNotes(){...};
       public Set getUrls(){...};
       public Set getTodos(){...};
    }
    puis une servlet dans laquelle je fait appel aux méthodes de ma classe service, donc qq chose comme ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    doGet(HttpServletRequest request, HttpServletResponse response){
     
    getFiles();
    getNotes();
    getUrls();
    getTodos();
     
    }
    j'ai remarqué qu'à chaque appel d'une méthode get une session est ouverte puis refermé ce qui fait que j'ai une succession d'ouvertures et de fermetures de sessions. Ne connaissant pas très bien la gestion des transactions je me demande si c'est quelque chose de gênant. ça me parait pas terrible.
    Après quelques recherches j'ai trouvé le Open Session in View pattern qui ouvre une session pour toute la durée de la requête (la requete http prise en charge par la servlet) et la ferme à la fin. Je n'arrive pas à le mettre en place car je ne dispose pas d'une sessionFactory mais d'un transactionManager.
    Est-ce qu'il y a un moyen d'obtenir le même résultat par configuration du transactionManager?

    Merci pour toute aide, je suis à la recherche des meilleurs pratiques pour gérer les transactions dans une appli web

  2. #2
    Expert confirmé
    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
    Par défaut
    Salut,
    Comment récupères tu le service dans la servlet ?

    Après quelques recherches j'ai trouvé le Open Session in View pattern qui ouvre une session pour toute la durée de la requête (la requete http prise en charge par la servlet) et la ferme à la fin. Je n'arrive pas à le mettre en place car je ne dispose pas d'une sessionFactory mais d'un transactionManager.
    Non, ça c'est autre chose, la session en question est une session de persistance, pas une session web et ça s'applique à JPA/Hibernate.

    [edit]
    Maintenant que j'y pense, tu ne serais pas en train de parler de session Hibernate ou JPA quand tu dis :
    j'ai remarqué qu'à chaque appel d'une méthode get une session est ouverte puis refermé

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut
    Merci pour ton retour djo.mos

    En fait oui je parle de session de persistance hibernate, j'ai expliqué comme un pied. J'utilise JPA + Hibernate.
    Je récupère le service par injection spring dans ma servlet.

    Qu'est ce que tu penses de la succession d'ouvertures et de fermetures de sessions de persistance? ça fait plusieurs jours que j'essaie d'avoir un avis sur la question sur le forum spring community mais sans succès.

  4. #4
    Expert confirmé
    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
    Par défaut
    Bah je sais pas, t'as fait REQUIRES_NEW sur les annotations Transactional ? et quel est le scope de ton service ?

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut
    non pas de REQUIRES_NEW, juste @Transactional au dessus de la définition de ma classe.

    je ne comprends pas bien la question sur le scope. je défini le service comme un bean dans le fichier de configuration spring applicationContext.xml puis je l'injecte dans les différentes servlet de mon appli donc je dirais scope application.

    ma servlet ressemble à ça (j'ai pas le code sous les yeux):

    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
    class MyServlet extends HttpServlet{
     
        Service myservice;
     
        public void setMyService(Service service){
            myservice = service;
       }
     
     
      public void doGet(HttpServletRequest request, HttpServletResponse response){
     
               String id = request.getParameter("id");
     
               myservice.getFiles(Integer.parseInt(id));
               myservice.getNotes(Integer.parseInt(id));
               myservice.getUrls(Integer.parseInt(id));
               myservice.getTodos(Integer.parseInt(id));
     
      }
     
    }

    en fait j'ai un POJO comme 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
    @Entity
    class Technology{
     
        String id;
     
        @ManyToMany
        Set notes = new HashSet();
        @ManyToMany
        Set files = new HashSet();
        @ManyToMany
        Set todos = new HashSet();
        @ManyToMany
        Set urls= new HashSet();
     
       //tous les getters et setters
     
    }
    je suis en train de me demander si je ne devrais pas écrire ma servlet comme ceci pour seulement ouvrir une session de persistance :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      public void doGet(HttpServletRequest request, HttpServletResponse response){
     
               String id = request.getParameter("id");
     
               Technology tech = myservice.getTechnology(Integer.parseInt(id));
     
               tech.getFiles();
               tech.getNotes();
               tech.getUrls();
               tech.getTodos();
     
      }

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut
    personne pour m'aider

    ce week end je vais mesurer les performances entre :

    succession de open/close hibernate session
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
      public void doGet(HttpServletRequest request, HttpServletResponse response){
     
               String id = request.getParameter("id");
     
               myservice.getFiles(Integer.parseInt(id));
               myservice.getNotes(Integer.parseInt(id));
               myservice.getUrls(Integer.parseInt(id));
               myservice.getTodos(Integer.parseInt(id));
     
      }
    et

    1 seule session hibernate ouverte
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      public void doGet(HttpServletRequest request, HttpServletResponse response){
     
               String id = request.getParameter("id");
     
               Technology tech = myservice.getTechnology(Integer.parseInt(id));
     
               tech.getFiles();
               tech.getNotes();
               tech.getUrls();
               tech.getTodos();
     
      }

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 51
    Par défaut
    Salut,

    J'ai fais le même teste en utilisant JPA et Hibernate mais je n'ai pas ton problème !

    J'utilise les annotations et quand j'appelle mon service depuis mon controleur je n'ai pas les ouvertures et fermetures de sessions !

    Voici le code de mon service :

    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
     
    @Service("PersonService")
    public class PersonServiceImpl implements PersonService {
     
    	@Autowired
    	private PersonDao dao;
     
    	public void setDao(PersonDao dao) {
    		this.dao = dao;
    	}
     
           @Transactional(readOnly = true)
    	@SuppressWarnings("unchecked")
    	public List<Person> getAll() {
    		return dao.getAll();
    	}
     
    	@Transactional(readOnly = true)
    	public Person get(long id) {
    		return dao.get(id);
    	}
     
           @Transactional
           public void save(Person person) {
    		dao.save(person);
    	}
    Pourquoi tu ne passes pas par un DTO qui exécutera toutes tes méthodes de ton service en une seule fois ?

    Controleur -> DTO -> service

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut
    je ne sais pas très bien ce que c'est DTO, c'est data transfert object? on récupère un object qui contient toutes les infos nécessaires en une seule fois?
    c'est ce que je fait avec ce code je pense:

    Technology tech = myservice.getTechnology(Integer.parseInt(id));

    Sinon, qu'est ce que tu fais dans ton controller? Tu appelles un ou plusieurs services? Mon souci c'est que j'appelle plusieurs méthodes de service et à chaque fois il y a une ouverture de session puis fermeture.

    De plus dans mes méthodes de service, j'effectue un clone des objets retournés par hibernate, ça force hibernate à effectuer les requetes pour récuperer les collections et éviter les lazy initialisation par la suite. c'est une bidouille et je ne sais pas du tout si c'est une bonne pratique.

  9. #9
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut
    cette histoire de session ne me sort pas de la tête

    j'ai mis en place un outil de pooling de sessions (c3p0) et j'essaie d'analyser les logs en mode debug, voici ce que j'ai quand j'appelle une méthode de ma classe service :

    INFO: 21:04:36,448 DEBUG JDBCTransaction:54 - begin
    INFO: 21:04:36,449 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6f76dd71 [managed: 5, unused: 4, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@5511e6b9)
    INFO: 21:04:36,450 DEBUG JDBCTransaction:59 - current autocommit status: true
    INFO: 21:04:36,451 DEBUG JDBCTransaction:62 - disabling autocommit
    INFO: Hibernate: select technology0_.id as id0_0_, technology0_.name as name0_0_ from TECHNO technology0_ where technology0_.id=?
    INFO: Hibernate: select files0_.TECHNO_id as TECHNO1_1_, files0_.files_id as files2_1_, file1_.id as id4_0_, file1_.date as date4_0_, file1_.description as descript3_4_0_, file1_.location_on_disk as location4_4_0_, file1_.name as name4_0_, file1_.name_on_disk as name6_4_0_ from TECHNO_FILE files0_ left outer join FILE file1_ on files0_.files_id=file1_.id where files0_.TECHNO_id=?
    INFO: Hibernate: select notes0_.TECHNO_id as TECHNO1_1_, notes0_.notes_id as notes2_1_, note1_.id as id1_0_, note1_.date as date1_0_, note1_.title as title1_0_, note1_.value as value1_0_ from TECHNO_NOTE notes0_ left outer join NOTE note1_ on notes0_.notes_id=note1_.id where notes0_.TECHNO_id=?
    INFO: Hibernate: select todos0_.TECHNO_id as TECHNO1_1_, todos0_.todos_id as todos2_1_, todo1_.id as id3_0_, todo1_.date as date3_0_, todo1_.done as done3_0_, todo1_.text as text3_0_ from TECHNO_TODO todos0_ left outer join TODO todo1_ on todos0_.todos_id=todo1_.id where todos0_.TECHNO_id=?
    INFO: Hibernate: select urls0_.TECHNO_id as TECHNO1_1_, urls0_.urls_id as urls2_1_, url1_.id as id2_0_, url1_.comment as comment2_0_, url1_.date as date2_0_, url1_.title as title2_0_, url1_.value as value2_0_ from TECHNO_URL urls0_ left outer join URL url1_ on urls0_.urls_id=url1_.id where urls0_.TECHNO_id=?
    INFO: 21:04:36,575 DEBUG JDBCTransaction:103 - commit
    INFO: 21:04:36,576 DEBUG JDBCTransaction:193 - re-enabling autocommit
    INFO: 21:04:36,577 DEBUG JDBCTransaction:116 - committed JDBC Connection


    j'ai une question, quand je vois ce log :
    INFO: 21:04:36,448 DEBUG JDBCTransaction:54 - begin
    est-ce que cela correspond à la création d'une session de persistance ou pas forcément? en utilisant c3p0 et son pool de sessions :

    INFO: 21:04:36,449 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6f76dd71 [managed: 5, unused: 4, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@5511e6b9)
    je me dis que la session est déjà créée mais je n'en suis pas sur du tout, et rien ne me le dit vraiment dans les logs. Qqn peut m'aider à interpreter les logs.

  10. #10
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut
    bon, j'ai lancé mon serveur avec un maximum de logs, première chose j'ai vu ceci

    INFO: 23:45:07,971 INFO SettingsFactory:147 - Automatic session close at end of transaction: disabled
    ça veut donc dire que la fin d'une transaction JDBC n'est pas synonime de fermeture de session vers la base de données. c'est bon à savoir.

    Puis j'ai vu tout un tas de log c3p0 où il récupère 5 resources de connections :

    INFO: 23:45:13,241 DEBUG C3P0PooledConnectionPool:217 - com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager@40ca6f53.acquireResource() returning.
    INFO: 23:45:13,241 DEBUG C3P0PooledConnectionPool:217 - com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager@40ca6f53.acquireResource() returning.
    INFO: 23:45:13,241 DEBUG C3P0PooledConnectionPool:217 - com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager@40ca6f53.acquireResource() returning.
    INFO: 23:45:13,246 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6342f024 [managed: 1, unused: 1, excluded: 0]
    INFO: 23:45:13,247 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6342f024 [managed: 1, unused: 0, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@59377ac0)
    INFO: 23:45:13,248 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6342f024 [managed: 2, unused: 1, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@59377ac0)
    INFO: 23:45:13,256 DEBUG C3P0PooledConnectionPool:217 - com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager@40ca6f53.acquireResource() returning.
    INFO: 23:45:13,256 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6342f024 [managed: 3, unused: 2, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@59377ac0)
    INFO: 23:45:13,258 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6342f024 [managed: 4, unused: 3, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@59377ac0)
    INFO: 23:45:13,260 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6342f024 [managed: 4, unused: 3, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@59377ac0)
    INFO: 23:45:13,262 DEBUG C3P0PooledConnectionPool:217 - com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager@40ca6f53.acquireResource() returning.
    INFO: 23:45:13,263 DEBUG BasicResourcePool:1644 - trace com.mchange.v2.resourcepool.BasicResourcePool@6342f024 [managed: 5, unused: 5, excluded: 0] (e.g. com.mchange.v2.c3p0.impl.NewPooledConnection@59377ac0)
    je suppose que ces ConnectionResource sont les fameuses sessions dont j'essaie de comprendre le cycle de vie.

    Ma dernière interrogation est de savoir si une transaction JDBC est couteuse ou si c'est vraiment négligeable. Maintenant je sais que ma servlet ne crée pas de sessions de connection (celles ci sont créées au démarrage de l'appli et gérées par c3p0) par contre
    il y a plusieurs transactions JDBC. Si ce n'est pas couteux je laisse tel quel sinon il faut que je trouve un moyen de tout faire en une seule transaction

  11. #11
    Membre confirmé
    Profil pro
    Inscrit en
    Mars 2004
    Messages
    138
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2004
    Messages : 138
    Par défaut
    j'ai trouvé un site pas mal sur la question :

    Best practices to improve performance in JDBC
    http://www.precisejava.com/javaperf/j2ee/JDBC.htm

    celui-la va rester dans mes bookmarks. et donc pour répondre à ma question, si un commit est fait après chaque instruction cela dégrade les performances. cela tombe bien l'annotation @Transactional démarre la ransaction au début de la méthode et la termine à la fin par contre si on enchaine plusieurs méthodes @Transactional il y aura une sucession de transactions JDBC.

    bon aller j'arrete de me prendre la tête surtout qu'une requete ne prend que quelques centièmes de seconde avec mysql tournant sur la même machine que le serveur.

  12. #12
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2007
    Messages : 51
    Par défaut
    Merci pour tout ces éclaircissements. Néanmoins, Spring ouvre un pool de connections au lancement de l'application. Avant chaque transaction, il va se service dans le pool, il exécute sa transaction puis il restitue la connexion au pool.
    Donc il n'y a perte de ressources...

Discussions similaires

  1. Réponses: 2
    Dernier message: 22/07/2012, 00h24
  2. Réponses: 11
    Dernier message: 17/06/2008, 17h42
  3. forcer l'ouverture d'une nouvelle Session
    Par leo13 dans le forum ASP.NET
    Réponses: 4
    Dernier message: 22/09/2007, 15h11
  4. [VBA Excel] Ouverture d'une nouvelle session Excel
    Par fmartin dans le forum Macros et VBA Excel
    Réponses: 11
    Dernier message: 12/06/2007, 16h35
  5. [Cookies] Chaque page démarre une nouvelle session
    Par Invité dans le forum Langage
    Réponses: 3
    Dernier message: 21/01/2006, 22h17

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