-->
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.  [ 5 posts ] 
Author Message
 Post subject: Meme identite pour le JVM ?
PostPosted: Wed Oct 12, 2005 11:22 pm 
Newbie

Joined: Wed Oct 12, 2005 9:20 pm
Posts: 16
Location: Sydney
Hibernate version: 2.1.8

Code between sessionFactory.openSession() and session.close():
Code:
public Object retrieveObj(Class c, Long id) throws DAOException {
        Object obj = null;

        try {
            Session session = HibernateSession.currentSession();
            obj = session.load(c, id);
        } catch(HibernateException he) {
            throw new DAOException(he);
        }
        finally {
            closeSession();
        }
        return obj;
    }


Name and version of the database you are using: MySQL 4.0.24


Bonjour,

Je suis nouveau sur Hibernate et j'ai deja appris beaucoup de chose en quelques semaines, mais la, je trouve pas le solution par moi meme.


Je suis en train de developper une application Java utilisant SWT pour gerer des produits (disques durs, memoires, ...).

J'utilise des Table SWT pour afficher les differents produits.

Mon probleme arrive quand j'ai un produit qui peut etre vendu separement mais egalement vendu en tant que partie d'un aute produit.

Par exemple, j'ai un Enclosure (qui permet d'utiliser des disques durs de manieres externe) qui peut etre vendu "vide", mais egalement vendu en tant que produit complet, c'est a dire contenant un disque dur dedans.

Exemple :

Code:
public class Enclosure {
   Long id;
   String interfaceType;
   int usbPorts;
   int sataPorts;
   int fireWirePorts;
}

Code:
public class Hdd {
   Long id;
   int speed;
   int size;
   int serialNumber;
}

Code:
public class Product {
   Long id;
   Enclosure enclosure;
   Hdd hdd;
}



Lorsque je lance l'application, la liste des Enclosures, la liste des Hdds et la liste des Products sont chargees dans des Set. Je charge ces listes dans des Set pour eviter des acces trop frequents mais egalement pour eviter des temps de chargement et de filtrage des listes.

Les Enclosures contenant dans le Set d'Enclosures et les Enclosures contenu dans le Set de Product (en tant qu'attribut de Product) sont different du point de vue de la JVM. Ce qui est normale quand on lit la doc.


Lorsque je modifie un objet dans une des table SWT (par exemple j'ajoute un port USB a un Enclosure), cette objet sera modifie dans le Set des Enclosures, mais pas dans le Set des Products (toujours par rapport a la doc).


Question 1
Est-ce que le design que j'ai fait de l'application est mauvais ? C'est a dire est-ce qu'il est preferable d'acceder a la BDD pour chaque lecture/ecriture d'un objet ou plutot de faire comme j'ai : un Set qui se charge au debut et qui est MAJ (ainsi que l'objet en BDD) des qu'il est modifie ?

Question 2
Si mon design est bon, y a-t-il un moyen de mettre a jour toutes les references d'un objet dans tous les differents Set facilement (sans avoir a parcourir tous les Set) ?


Si je ne suis pas assez clair ou si vous avez d'autres informations ........

Merci d'avance.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 13, 2005 6:18 am 
Senior
Senior

Joined: Tue May 10, 2005 9:00 am
Posts: 125
Bonjour

Si tu as un Enclosure, disons avec l'id 1234, chargé dans le set des Enclosures et que, *durant la même session*, tu charge un product qui pointe sur un Enclosure ayant l'id 1234, alors c'est strictement le même object dans la jvm (et non pas deux objets différents contenant les même datas).

Pour faire clair,
Code:
   Object o1 = session.load(Enclosure.class, 1234);
   Object o2 = session.load(Enclosure.class, 1234);
   o1==o2; /*toujours vrai*/
   /* MAIS, si session1 et session2 sont deux session différentes:*/
   o1 = session1.load(Enclosure.class, 1234);
   o2 = session2.load(Enclosure.class, 1234);
   o1!=o2  /*session différente donc objets différents dans la jvm */


D'ailleurs la doc vers laquelle tu pointe stipule clairement que çà ne s'applique qu'en cas de sessions différentes :)

Donc pour solutionner ton problème, je dirais que le plus simple est de garantir que tout sois chargé dans la même session.
Je serais tenté de penser que cette partie du code:
Code:
        finally {
            closeSession();
        }

ferme systématiquement ta session après chaque chargement d'objet, ce qui n'est pas bien.

D'ailleurs si tu travaille avec des Set mais une seule session globale pour l'application (ce qui me semblerais logique), tu ne devrais pas avoir a te soucier du equals et du hashCode

En gros, Hibernate te garantit normalement, au sein d'une session, que tous les objets liés entre eux et lus depuis la db sont cohérents (un objet avec un id donné ne peux pas exister en plusieurs exemplaire, c'est une référence commune partagée aux différents endroits où ils sont utilisés).


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 13, 2005 8:06 pm 
Newbie

Joined: Wed Oct 12, 2005 9:20 pm
Posts: 16
Location: Sydney
Merci beaucoup pour ta reponse.

C'est ce que j'avais cru comprendre en lisant la doc.

Mais du coup, une autre question me vient a l'esprit :
A quelle moment est-il oportain de fermer/ouvrir la session.

Dans mon cas, j'utilise une classe HibernateSession qui se charge de la config et qui me donne la session en cours :
Code:
public class HibernateSession {
    public static final ThreadLocal session = new ThreadLocal();
    private static final Configuration cfg = new Configuration();
    private static SessionFactory sf;
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";

    /**
       Returns the ThreadLocal Session instance.  This method will initialize
       the <code>SessionFactory</code> if necessary.
       @return Session
       @throws DAOException
    */
    public static Session currentSession() throws HibernateException {
        Session s = (Session) session.get();

        try {
            if(s == null) {
                if (sf == null) {
                    try {
                        cfg.configure(CONFIG_FILE_LOCATION);
                        // Duplicate loading with the hibernate.cfg.xml mappings
                        //loadClasses();
                        sf = cfg.buildSessionFactory();
                    }
                    catch(Exception e) {
                        System.err.println("%%%% Error Creating SessionFactory %%%%");
                        e.printStackTrace();
                    }
                }
                s = sf.openSession();
                session.set(s);
            }
        }
        catch (HibernateException he) {
            throw he;
        }
        return s;
    }

    /**
       Closes the session object.
       @throws DAOException
    */
    public static void closeSession() throws HibernateException {
        Session s = (Session) session.get();
        session.set(null);

        if(s != null) {
            try {
                s.close();
            }
            catch (HibernateException he) {
                throw he;
            }
        }
    }
}


Ensuite, je cree une classe EnclosureFactory qui me retourne la liste des Enclosure (par exemple):
Code:
public class EnclosureFactory {
   .....
   public static List getList() throws DAOException {
      DataAccess da = new DataAccess();
      List list = da.retrieveObjs("from Enclosure", null);
      return list;
   }
   ....
}


DataAccess est une classe qui encapsule les methodes les plus courantes :
Code:
public class DataAccess {

   protected void removeObj(Class c, Long id) throws DAOException {
      try {
         Session session = HibernateSession.currentSession();
         // first load the object with the current session.
         // the object must be loaded in this session before it
         // is deleted.
         Object obj = session.load(c, id);
         session.delete(obj);
         session.flush();
         session.connection().commit();
      } catch (Exception e) {
         rollback();
         throw new DAOException(e);
      } finally {
         closeSession();
      }
   }

   public Object retrieveObj(Class c, Long id) throws DAOException {
      Object obj = null;

      try {
         Session session = HibernateSession.currentSession();
         obj = session.load(c, id);
      } catch (HibernateException he) {
         throw new DAOException(he);
      } finally {
         closeSession();
      }
      return obj;
   }

   public Object retrieveObj(String key, String value) throws DAOException {
      List objects = retrieveObjs(key, value);
      if (objects != null) {
         if (objects.size() == 0) {
            return null;
         } else {
            return objects.get(0);
         }
      } else {
         return null;
      }
   }

   public List retrieveObjs(String key, String value) throws DAOException {
      List results = null;

      try {
         Session session = HibernateSession.currentSession();
         if (value != null) {
            results = (List) session.find(getQuery(key), value, Hibernate.STRING);
         } else {
            results = (List) session.find(getQuery(key));
         }
      } catch (HibernateException he) {
         throw new DAOException(he);
      } finally {
         closeSession();
      }
      return results;
   }

   void storeObj(Object obj) throws DAOException {
      try {
         Session session = HibernateSession.currentSession();
         session.saveOrUpdate(obj);
         session.flush();
         session.connection().commit();
      } catch (HibernateException he) {
         rollback();
         throw new DAOException(he);
      } catch (SQLException sqle) {
         rollback();
         throw new DAOException(sqle);
      } finally {
         closeSession();
      }
   }

   private void closeSession() throws DAOException {
      try {
         HibernateSession.closeSession();
      } catch (HibernateException he) {
         throw new DAOException(he);
      }

   }

   private void rollback() throws DAOException {
      try {
         Session session = HibernateSession.currentSession();
         if (session != null) {
            session.connection().rollback();
         }
      } catch (HibernateException he) {
         throw new DAOException(he);
      } catch (SQLException sqle) {
         throw new DAOException(sqle);
      }
   }
}


Donc si je suis ton raisonnement, cette derniere classe est "fausse". Dans le sens ou elle ne devrait pas fermer la session.

Quand-est-ce qu'une session devrait etre fermee alors ?

Merci pour votre temps.


Ben


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 14, 2005 12:16 am 
Newbie

Joined: Wed Oct 12, 2005 9:20 pm
Posts: 16
Location: Sydney
J'ai retire tous les
Code:
}finaly{
   closeSession();
}
comme me l'a conseille Tchize et ce la fonctionne comme un charme.

Mais ma question est toujours d'actualite :
Quand est-ce que l'on ferme/ouvre une session ? Quel est le "meilleur moment" pour ca ?

Merci encore pour ton aide Tchize.


Ben


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 18, 2005 8:36 am 
Senior
Senior

Joined: Tue May 10, 2005 9:00 am
Posts: 125
Quand ouvre-t-on et quand ferme-t-on?

La question est assez complexe je dirais, tout dépend du type d'application.

En gros, tu ouvre la session avant le premier moment ou tu as besoin d'objets venant de la DB et tu la ferme quand tu as fini de les utiliser.

Si il s'agit d'une application type swing/awt, tu peux par exemple démarrer la session a l'ouverture de l'application et la fermer quand tu as fini de l'utiliser. Donc en gros

main
ouvrir session
utilisateur joue avec les objets
finally: fermer session

bien sur, ne pas faire de System.exit() dans ce cas ;)


Si tu utilise une web application, alors tu as deux possibilités

soit tu ouvre avant d'exécuter la requete http et tu la ferme juste après

soit tu stocke la session hibernate dans la session http la première fois ou tu en as besoin et tu la déconnecte (session.disconnect()) a la fin de la requete. A la requête suivante tu fait au début un session.reconnect(). Quand la session http est nettoyée (notification via HttpSessionBindingListener). Voir partie de la documentation sur les sessions longues.

Pour faire simple, tu garde la session ouverte jusqu'à ce que tu n'aie plus besoin des objets qui y sont associés. Il faut éviter de mixer les objets entre 2 sessions.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.