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