-->
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.  [ 2 posts ] 
Author Message
 Post subject: beginTransaction: Session is closed
PostPosted: Fri Jun 24, 2005 2:57 pm 
Regular
Regular

Joined: Sun May 08, 2005 2:48 am
Posts: 118
Location: United Kingdom
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");
      }
   }
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 24, 2005 4:23 pm 
Regular
Regular

Joined: Sun May 08, 2005 2:48 am
Posts: 118
Location: United Kingdom
I have changed the currentSession() function to detect a closed session and re-open it.

Is this a valid solution, does this turn my application into a session-per-transaction anti-pattern ?

Although my example show a single hsession.save() call, imagine this is truly a more complex unit-of-work that has no relationship to other units-of-work I'm trying to do in the same session.


My new Singleton that hides the implicit close being performed at Transaction.commit().


Code:
   public static Session currentSession() throws HibernateException {
      HibernateSessionRefCounted tlSession = (HibernateSessionRefCounted) sessionContext.get();

      // Don't get from JNDI, use a static SessionFactory
      SessionFactory sessionFactory = HibernateSessionFactory.getSessionFactory();

      if (sessionFactory == null) {
         // Generate an exception here
         throw new HibernateException("sessionFactory build failure");
      }

      if (tlSession == null) {
         tlSession = new HibernateSessionRefCounted();
         tlSession.internalOpenSession(sessionFactory);
      } else {
         if(tlSession.session.isOpen() == false) {
            log.debug("sesh=" + tlSession + "; l=" + tlSession.level + "; But session is closed, re-opening!");
            tlSession.internalOpenSession(sessionFactory);
         }
      }
      tlSession.level++;
      log.debug("sesh=" + tlSession + "; l=" + tlSession.level);
      return tlSession.session;
   }

private void internalOpenSession(SessionFactory sessionFactory) throws HibernateException {
      session = sessionFactory.openSession();
      level = 0;
      sessionContext.set(this);
   }


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