Using: Tomcat 5.5.9 + Hibernate 3.0.2 + JDBCTransaction
I am using session-per-request pattern.
I am using a reference counting version of HibernateSession Singleton (I believe this is what STRUTS uses, but I am not using STRUTS). This means I can call HibernateSession.currentSession() and HibernateSession.closeSession() in pairs around my units-of-work.
During a single request multiple transactions are being run, these are my atomic units or work. I am using the HibernateSession.beginTransaction() at the begin part of each transaction then the Transaction.commit() to commit. This is how I believe I should de-mark my transactions.
However at the second call to HibernateSession.beginTransaction() when reusing the same HibernateSession I get a HibernateException that "Session is closed".
There was no exception thrown before this and the first Transaction.commit() was a complete sucess and the data in the database.
Any pointers appreciated,
Thanks,
Darryl
I enclose the code snippets in execution order of my program:
Code:
... request setup ...
Session hsession_outer = HibernateSession.currentSession(); // This opens a session
... I need to do a transaction ...
Session hsession = null;
try {
hsession = HibernateSession.currentSession(); // This just gets the same session, bumps up ref counter
Transaction tx = hsession.beginTransaction(); // No error
hsession.save(rec);
tx.commit(); // No error
} catch (RuntimeException e) {
log.warn("RuntimeException occured");
throw e; // or display error message
} finally {
HibernateSession.closeSession(); // This released the refence count, but does not call close()
hsession = null;
}
...some more code here... then another transaction ...
Session hsession = null;
try {
hsession = HibernateSession.currentSession(); // This just gets the same session, bumps up ref counter
//////////////////////// PROBLEM AREA ///////////////////////////////////
Transaction tx = hsession.beginTransaction(); [b]// This generates my exception[/b]
//////////////////////// PROBLEM AREA ///////////////////////////////////
hsession.save(rec);
tx.commit();
} catch (RuntimeException e) {
log.warn("RuntimeException occured");
throw e; // or display error message
} finally {
HibernateSession.closeSession(); // This released the refence count, but does not call close()
hsession = null;
}
...and finally....
HibernateSession.closeSessionForced(); // This releases the refence count to zero, so this one will call close() proper.
hsession_outer = null;
My Singleton implementation, just in case I did not get it right:
Code:
import org.hibernate.SessionFactory;
import org.hibernate.HibernateException;
import org.hibernate.Session;
public class HibernateSessionRefCounted {
private static org.apache.commons.logging.Log log =
org.apache.commons.logging.LogFactory.getLog(HibernateSessionRefCounted.class);
private static final ThreadLocal sessionContext = new ThreadLocal();
private Session session;
private int level;
public static Session currentSession() throws HibernateException {
HibernateSessionRefCounted tlSession = (HibernateSessionRefCounted) sessionContext.get();
if (tlSession == null) {
// Don't get from JNDI, use a static SessionFactory
SessionFactory sessionFactory = HibernateSessionFactory.getSessionFactory();
if (sessionFactory != null) {
tlSession = new HibernateSessionRefCounted();
tlSession.session = sessionFactory.openSession();
tlSession.level = 0;
sessionContext.set(tlSession);
} else {
// Generate an exception here
throw new HibernateException("sessionFactory failed build");
}
}
tlSession.level++;
log.debug("sesh=" + tlSession + "; l=" + tlSession.level);
return tlSession.session;
}
public static void closeSession() throws HibernateException {
HibernateSessionRefCounted tlSession = (HibernateSessionRefCounted) sessionContext.get();
log.debug("sesh=" + tlSession + "; l=" + ((tlSession != null) ? tlSession.level : -1));
if (tlSession != null) {
tlSession.level--;
if (tlSession.level <= 0) {
if (tlSession.session != null && tlSession.session.isOpen()) {
tlSession.session.close();
tlSession.session = null;
}
sessionContext.set(null);
}
}
}
public static void closeSessionForced() throws HibernateException {
HibernateSessionRefCounted tlSession = (HibernateSessionRefCounted) sessionContext.get();
if (tlSession != null) {
log.debug("sesh=" + tlSession + "; l=" + tlSession.level + "; op=" + ((tlSession.level != 1) ? "BAD" : "GOOD"));
if (tlSession.session != null && tlSession.session.isOpen()) {
tlSession.session.close();
tlSession.session = null;
}
sessionContext.set(null);
} else {
log.debug("sesh=NULL");
}
}
}