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