-->
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.  [ 4 posts ] 
Author Message
 Post subject: Thread Local Session: can't get opened session
PostPosted: Fri Nov 07, 2003 11:22 am 
Regular
Regular

Joined: Fri Nov 07, 2003 6:31 am
Posts: 104
Location: Beijing, China
I recently had pbs with this pattern
While trigerring a search form repetitively with the same parameter, I got different results.
I finally found out that the find() method of my DAO was not always using the same session.

When analysing the behavior of the pattern, i realised that it does not always retrieve the existing Session, which lead to inconsistencies.
(it sometimes open a new Session whereas another one is available)

So even when doing the same simple repetitive find() , i'm not systematicaly getting the same object, which of course leads to functionnal mistakes

Here's my code:
Environment:
Jsk1.4.2
Hibernate 2.0.3
Struts1.1
SQLServer

System:
I'm using the Thread Local Session pattern implemented as follow:
Code:
public class ServiceLocator {
    //~ Static fields/initializers =============================================

    public static final ThreadLocal session = new ThreadLocal();
    private static SessionFactory sf = null;
    private static ServiceLocator me;
    private static Log log = LogFactory.getLog(ServiceLocator.class);

    static {
        try {
            me = new ServiceLocator();
        } catch (Exception e) {
            log.fatal("Error occurred initializing ServiceLocator");
            e.printStackTrace();
        }
    }

    //~ Constructors ===========================================================

    private ServiceLocator() throws HibernateException, JDBCException {
        // Try to lookup a JNDI Connection
        try {
            log.debug("Looking up Session in JNDI");
            sf = (SessionFactory) new InitialContext().lookup(org.xx.common.Constants.SESSION_FACTORY);
        } catch (NamingException ne) {
            log.info("error communicating with JNDI, assuming testcase");

            /* If you don't want to specify full class names here and in your DAO's, add
               the following to your hibernate.properties file:
               hibernate.query.imports=org.appfuse.persistence
             */
            sf = new Configuration().addClass(org.xx.adherent.model.Adherent.class)
                    .addClass(org.xx.of.model.Affactureur.class)
                    .addClass(org.xx.adherent.model.CodeFormeJuridique.class)
                    .addClass(org.xx.adherent.model.CodeOrganismeTiersAlternance.class)
                    .addClass(org.xx.of.model.CodeRegroupementOf.class)
                    .addClass(org.xx.profession.model.CodeRisqueNonVersement.class)
                    .addClass(org.xx.of.model.CodeTypeTva.class)
                    .addClass(org.xx.of.model.ConventionCadre.class)
                    .addClass(org.xx.profession.model.NatureFonds.class)
                    .addClass(org.xx.of.model.OrganismeFormation.class)
                    .addClass(org.xx.profession.model.OrganismeTiersCollecteur.class)
                    .addClass(org.xx.profession.model.Profession.class)
                    .addClass(org.xx.adherent.model.Properties.class)
                    .addClass(org.xx.profession.model.RegroupementProfession.class)
                    .addClass(org.xx.user.model.Role.class)
                    .addClass(org.xx.profession.model.Section.class)
                    .addClass(org.xx.adherent.model.StatutCotisation.class)
                    .addClass(org.xx.adherent.model.StatutDemandeFormationSansCotisation.class)
                    .addClass(org.xx.adherent.model.StatutDepassementSeuil.class)
                    .addClass(org.xx.adherent.model.StatutEnvoiBv.class)
                    .addClass(org.xx.adherent.model.StatutNonCotisant.class)
                    .addClass(org.xx.profession.model.TauxCotisation.class)
                    .addClass(org.xx.user.model.User.class)
                    .buildSessionFactory();
        }
    }

    //~ Methods ================================================================

    public static Session currentSession() throws HibernateException {
        Session s = (Session) session.get();
        log.debug("Got hibernate session : "+ s);

        if (s == null) {
            s = sf.openSession();
            log.debug("Opened hibernate session.");
            session.set(s);
        }
        return s;
    }

    public static void closeSession() throws HibernateException, JDBCException {
        Session s = (Session) session.get();
        session.set(null);

        if (s != null) {
            s.close();
            log.debug("Closed hibernate session.");
        }
    }
}


The session are obtained only in the Struts Actions by calling a ActionFilter.getSessions:

Code:
public class ActionFilter implements Filter {

    private static Log log = LogFactory.getLog(ActionFilter.class);
    private FilterConfig filterConfig = null;

    //~ Methods ================================================================

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;

    }

    /**
     * Destroys the filter.
     */
    public void destroy() {
        filterConfig = null;
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
    throws IOException, ServletException {
     //do some stuff
    }

    public static Session getSession() throws Exception {
      try {
           return ServiceLocator.currentSession();
      } catch (HibernateException he)
      {
         log.error("Error retrieving an Hibernate Session :" + he.getMessage());
         throw new Exception(he);
      }
    }
}


My DAO method is implemented as follow:
Code:
   public List findObject(Session ses, Class clazz, HashMap map) throws DAOException {
      List classList = null;

      String sql = " 0=0 ";
      Iterator i = map.keySet().iterator();
      while (i.hasNext()) {
         String param = i.next().toString();
         String operator = param.substring(0,1);
            if (operator.compareTo("%")==0) {
               sql = sql + " AND clazz." + param.substring(1) + " like '" + map.get(param) + "%'";
            } else {
               sql = sql + " AND clazz." + param + " = '" + map.get(param) + "'";
            }
      }
      try {
         System.out.println("Sessioon : " +ses);
            classList = ses.find("from clazz in " + clazz + " where " + sql);

      } catch (Exception e) {
         throw new DAOException(e);
      }
      return classList;
   }

NB: I'm not closing the session since it's not necessary when only reading the DB

Here the log I get when i do a repetitive call to this method:
Code:
14:40:14,868 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
14:40:14,868 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
Sessioon : net.sf.hibernate.impl.SessionImpl@24bfaa
search
14:40:16,618 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
14:40:16,618 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
Sessioon : net.sf.hibernate.impl.SessionImpl@24bfaa
search
14:40:17,711 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
14:40:17,711 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
Sessioon : net.sf.hibernate.impl.SessionImpl@24bfaa
search
14:40:18,477 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
14:40:18,477 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
Sessioon : net.sf.hibernate.impl.SessionImpl@24bfaa
search

<this time does not find the session and open a new one. How come??>
14:40:19,024 DEBUG ServiceLocator:82 - Got hibernate session : null
14:40:19,024 DEBUG ServiceLocator:86 - Opened hibernate session.
14:40:19,024 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@1a01e8a
Sessioon : net.sf.hibernate.impl.SessionImpl@1a01e8a
search

Code:
14:40:19,571 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
14:40:19,571 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@24bfaa
Sessioon : net.sf.hibernate.impl.SessionImpl@24bfaa
search
14:40:20,118 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@1a01e8a
14:40:20,118 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@1a01e8a
Sessioon : net.sf.hibernate.impl.SessionImpl@1a01e8a
search
14:40:21,430 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@1a01e8a
14:40:21,430 DEBUG ServiceLocator:82 - Got hibernate session : net.sf.hibernate.impl.SessionImpl@1a01e8a
Sessioon : net.sf.hibernate.impl.SessionImpl@1a01e8a
search


Anyhelp would be more than welcome.
Otherwise i'll have to systematically close all the session, which is not appealing!

cheers,
nodje


Last edited by nodje on Tue Jun 03, 2008 5:29 am, edited 2 times in total.

Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 07, 2003 1:40 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
Ther will be one thread per http connection so one open session per connection. You need to close Hibernate session at the end of your chained action.

_________________
Emmanuel


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 07, 2003 2:19 pm 
Regular
Regular

Joined: Fri Nov 07, 2003 6:31 am
Posts: 104
Location: Beijing, China
I dont see any problem in having one open session per connection.
As far as I understood, it was essential to close the session after a flush() or commit() but not necessary in th other cases.
Is that right?

BUt what you seems to suggest is that, if a user updates an object (so uses its session and close it), all the other users that are using a session opened before the update won't see the updated object but the old one?? Does that make sense?

As for closing the sessions at the end of my chained actions, it basically means closing session after each CRUD operation in my DAO classes.
Then I lose any interest in using THreadLocal Session pattern I think.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Nov 07, 2003 2:30 pm 
Hibernate Team
Hibernate Team

Joined: Sun Sep 14, 2003 3:54 am
Posts: 7256
Location: Paris, France
nodje wrote:
I dont see any problem in having one open session per connection.

Me neither, that's what I do.

nodje wrote:
As far as I understood, it was essential to close the session after a flush() or commit() but not necessary in th other cases. Is that right?

This behabiour will result in a DB connection leak. A session has 1 DB connection, so it is fontamental to close it.
The recommanded way is to open the session for a business tx, and close it asap. If you need to have "long" tx, use session.disconnect() and session.reconnect().

nodje wrote:
BUt what you seems to suggest is that, if a user updates an object (so uses its session and close it), all the other users that are using a session opened before the update won't see the updated object but the old one??

Yes if they load it before the other session.flush()
nodje wrote:
Does that make sense?

Yes, this is a common problem of DB usage. To prevent such inconsistency, you can use pessimistic lock (DB managed), or optinistic lock (version or timestamp comparison before update).

nodje wrote:
As for closing the sessions at the end of my chained actions, it basically means closing session after each CRUD operation in my DAO classes.
Then I lose any interest in using THreadLocal Session pattern I think.

If your app is as simple as user CRUD on one object (no persistable manipulation of object model outside 1 DAO), so yes it's useless.

_________________
Emmanuel


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