-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Problème de résultats différents à l'appel d'une requete
PostPosted: Tue Feb 21, 2006 5:52 pm 
Newbie

Joined: Tue Feb 21, 2006 5:13 pm
Posts: 2
Bonjour a tous,
j'ai un curieux problème :

je développe une application web (tomcat 5, struts 1.1, hibernate 2.0, postgresql) dans laquelle je lis et je modifie un bean User tout simple. Lorsque je modifie la valeur d'une propriété de ce bean puis que je l'update, l'entrée est bien modifiée en base. Par contre, quand je le relis plusieurs fois de suite, j'obtiens de temps en temps les anciennes valeurs de la propriété modifiée, d'autres fois la nouvelle valeur. En modifiant et updatant plusieurs fois, ma base est toujours correctement updatée mais les relectures me donnent un peu n'importe quelle valeur précédente.
Je crois que le problème vient peut-être de ce que je n'ai pas bien compris quand refermer mes sessions (dois-je les refermer après chaque transaction ou est-ce que je dois garder la même session hibernate pour une session tomcat).
Un peu de code sera plus parlant :

Le mapping de mon User :

Code:
   <class name="atr.metier.User" table="tab_user">
      <id name="id" type="long" column="user_id" unsaved-value="0">
         <generator class="sequence">
            <param name="sequence">seq_user</param>
         </generator>
      </id>
      <property name="userName" column="user_name"/>
      <property name="password" column="user_pass"/>
      <property name="firstName" column="user_fname"/>
      <property name="lastName" column="user_lname"/>
      <property name="email" column="user_mail"/>
      <property name="nbPicsParPage" column="user_nbpics"/>
      <property name="style" column="user_style"/>
      <property name="registrationDate" column="user_reg_date"/>
      <property name="admin" column="user_admin"/>
   </class>


Le equals de mon User (qui n'est que getter et setter par ailleurs):
Code:
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof User)) {
            return false;
        }
        final User that = (User) obj;
        return (getPassword() == null && that.getPassword() == null || getPassword() != null
                && getPassword().equals(that.getPassword()))
                && (getEmail() == null && that.getEmail() == null || getEmail() != null
                        && getEmail().equals(that.getEmail()))
                && (getFirstName() == null && that.getFirstName() == null || getFirstName() != null
                        && getFirstName().equals(that.getFirstName()))
                && (getLastName() == null && that.getLastName() == null || getLastName() != null
                        && getLastName().equals(that.getLastName()))
                && (getUserName() == null && that.getUserName() == null || getUserName() != null
                        && getUserName().equals(that.getUserName()))
                && (getNbPicsParPage() == null && that.getNbPicsParPage() == null || getNbPicsParPage() != null
                        && getNbPicsParPage().equals(that.getNbPicsParPage()))
                && (getStyle() == null && that.getStyle() == null || getStyle() != null
                        && getStyle().equals(that.getStyle()))
                && (getAdmin() == null && that.getAdmin() == null || getAdmin() != null
                        && getAdmin().equals(that.getAdmin()))
                && (getRegistrationDate() == null && that.getRegistrationDate() == null || getRegistrationDate() != null
                        && getRegistrationDate().equals(that.getRegistrationDate()));
    }


Les méthodes de lecture et d'update :

Code:
    public static void modifyUser(User user) throws HibernateException {
        if (user != null) {
            HibernateSessionFactory.closeSession();
            Session session = HibernateSessionFactory.currentSession();
            Transaction tx = session.beginTransaction();
            session.saveOrUpdate(user);
            tx.commit();
            HibernateSessionFactory.closeSession();
        }
    }

    public static Collection getUsers() throws HibernateException {
        List result = null;
        Session session = HibernateSessionFactory.currentSession();
        Transaction tx = session.beginTransaction();
        result = session.createQuery("from atr.metier.User").list();
        tx.commit();
        return result;
    }



Si par exemple mon bean a la propriété style fixée à "Jaune", que je la passe à "Bleu", que j'update via modifyUser, la base est mise à jour ; si j'appelle getUsers, le User que je récupère de la liste est parfois à "Jaune", parfois à "Bleu", sans que je comprenne pourquoi l'une ou pouquoi l'autre.

Merci de votre aide.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 22, 2006 8:52 am 
Senior
Senior

Joined: Tue May 10, 2005 9:00 am
Posts: 125
C'est parce que tu as plusieurs session hibernate ouvertes et que tu as donc récupéré plusieurs exemplaires du bean en mémoire. Je gage que tu a lié la session Hibernate au Thread (pattern ThreadLocal?). Tomcat utilisant un Thread pool tu tombe une fois sur le thread 1 une fois sur le 2, etc, à chaque fois avec une session différente. Certaines sont 'vieille' et donc ont chargé ton bean User avant que tu ne le modifie, d'autre sont plus récentes et on chargé la nouvelle valeur.

Je gage que tout ton problème se trouve dans HibernateSessionFactory.

Tu pourrais croire que result = session.createQuery("from atr.metier.User").list(); va d'office relire la DB, mais ce n'est pas entièrement vrai. Ca va récupérer les ID seulement. Ensuite, Hibernate va mettre dans la liste un objet User pour chaque ID. ET c'est là ton problème, si l'ID est déjà dans la session il va récupérer le User associé à la Session sans rien relire de la DB. (Hibernate garanti en fait que chaque ID ne peut se voir associer qu'un seul objet dans une session -> il récupère le vieux User)

Suggestion:

Soit tu clot la session à la fin de la requete (çà garanti qu'elle ne sera plus utilise lors des requêtes suivant et évite ce phénomène de caching). Soit tu accepte qu'il y aie ce caching et, si tu veux des valeurs à jour dans un objet, tu fais un session.refresh(object);

PS: pourquoi pas hibernate 3?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Feb 22, 2006 9:26 am 
Newbie

Joined: Tue Feb 21, 2006 5:13 pm
Posts: 2
Merci pour ta réponse très claire. Effectivement j'utilise le pattern ThreadLocal, et conformément à ta suggestion, je pense que je vais faire des refresh pour continuer à bénéficier du cache quand mon objet n'est pas modifié (ce qui est le cas la plupart du temps).

Pourquoi Hibernate 2 ? car la version de MyEclipse que j'ai et qui ajoute automatiquement les jar hibernate contient la v2 :) C'est vrai que je devrais quand même passer en 3.

Encore merci


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.