Results 1 to 7 of 7

Thread: How to check there already is Hibernate session for thread?

  1. #1
    Join Date
    Oct 2004
    Posts
    5

    Default How to check there already is Hibernate session for thread?

    I'd like to be able to know if there already is a Hibernate session assigned for current thread or not. Currently, if I do getSession() for SessionFactoryUtils when there is no session bound to thread, it will either create a new session or throw InvalidStateException, depending on whether we allow creation of new sessions or not.

    What I would like to do is write code that could either participate already existing session (just access the data, no flush() or close()), or if there isn't one, create it locally, use it, and finally do flush() and close(). In other words, if there is session, let it be managed outside my code and if not, create and manage session locally.

    This way, I could reuse the code as 'standalone' or part of larger process, possibly part of a transaction.

    Any ideas?

  2. #2
    Join Date
    Aug 2004
    Location
    San Mateo, CA
    Posts
    1,265

    Default

    Sounds like you want the PROPAGATION_SUPPORTS behaviour. See org.springframework.transaction.TransactionDefinit ion. You can use this declaratively.
    Rod Johnson - GM, SpringSource Division, VMware
    http://www.springsource.com
    Spring From the Source

  3. #3
    Join Date
    Oct 2004
    Posts
    5

    Default

    Not really, or I didn't understand it correctly.

    My key point was not about transactions. I just would like to be able to use same piece of code both when I have declarative transactions (and thus Hibernate sessions) and when there are no thread bound sessions at all.

    I would execute my code using a callback, using code like this:

    Code:
        public static void doInSession(HibernateSessionWork work) {
            if (work == null)
                throw new IllegalArgumentException("Work can not be null");
    
            try {
                Session session = HibernateUtils.sessionFactory.openSession();
                if (session != null) {
                    try {
                        work.doInSession(session);
                        session.flush();
                    } finally {
                        session.close();
                    }
                } else
                    throw new RuntimeException("Could not get Hibernate session");
            } catch (HibernateException e) {
                throw SessionFactoryUtils.convertHibernateAccessException(e);
            }
        }
    Code above only manages sessions locally. What I would like to do is use thread local session if it's available, but I can't do that because SessionFactoryUtils doesn't allow me to just check whether there is a session bound to current thread or not. Ofcourse, if there is a session bound to the thread, I wouldn't do flush() nor close().

  4. #4
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    You can use the same code that SessionFactoryUtils does, to see if there is a bound session:

    SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sess ionFactory);

    If sessionHolder is non-null, there is a bound session...

    Probably best to put this in a wrapper method, if you use it from more than one place.
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

  5. #5
    Join Date
    Oct 2004
    Posts
    5

    Default

    Thanks! This seems to be what I was looking for.

  6. #6
    Join Date
    Oct 2004
    Posts
    5

    Default

    Ok, here's my current wrapper method:

    Code:
        public static void executeInSession(HibernateSessionWork work) {
            if (work == null)
                throw new IllegalArgumentException("Work can not be null");
    
            try {
                //use thread bound session if it's available
                SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
                boolean localSession = (sessionHolder == null);
                Session session = SessionFactoryUtils.getSession(HibernateUtils.sessionFactory, localSession);
    
                //if we created session locally, we need to bind it to thread
                if (localSession) {
                    sessionHolder = new SessionHolder(session);
                    TransactionSynchronizationManager.bindResource(sessionFactory, sessionHolder);
                }
    
                if (session != null) {
                    try {
                        //pass session factory to work
                        work.setSessionFactory(HibernateUtils.sessionFactory);
                        //do stuff that uses session
                        work.execute();
                        if (localSession)
                            session.flush();
                    } finally {
                        //cleanup
                        work.setSessionFactory(null);
    
                        if (localSession) {
                            session.close();
                            TransactionSynchronizationManager.unbindResource(sessionFactory);
                        }
                    }
                } else
                    throw new RuntimeException("Could not get Hibernate session");
            } catch (HibernateException e) {
                throw SessionFactoryUtils.convertHibernateAccessException(e);
            }
        }
    And the skeleton class for work is:

    Code:
    public abstract class HibernateSessionWork {
        private static final Log logger = Logging.getLog(HibernateSessionWork.class);
    
        private SessionFactory sessionFactory;
    
        void setSessionFactory(SessionFactory sessionFactory) {
            this.sessionFactory = sessionFactory;
        }
    
        /**
         * Get an instance of HibernateTemplate, bound to current session.
         *
         * @return
         */
        public final HibernateTemplate getHibernateTemplate() {
            return new HibernateTemplate(this.sessionFactory, false);
        }
    
        /**
         * Get the current Hibernate session.
         *
         * @return
         */
        public final Session getSession() {
            SessionHolder sessionHolder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
            return sessionHolder.getSession();
        }
    
        /**
         * To be used with <code>HibernateUtils.executeInSession&#40;&#41;</code>. Encapsulate
         * a piece of work that requires a Hibernate session, without actually
         * doing session management.
         *
         * To actually access Hibernate, implementation should get instances of Session and 
         * HibernateTemplate using <code>getSession&#40;&#41;</code> and <code>getHibernateTemplate</code>.
         *
         * If this method throws an exception, session will NOT be flushed to database
         * &#40;but it will be closed, still&#41;.
         */
        public abstract void execute&#40;&#41;;
    &#125;
    Does this seem to be right? I'm a bit concerned about the lines that call TransactionSychronizationManager - if sessions are managed locally, there are no transactions and calling TSM sounds scary to me.. Am I potentially breaking something because of (un)bindResource() calls?

  7. #7
    Join Date
    Aug 2004
    Location
    Toronto, Canada
    Posts
    736

    Default

    On a cursory look, your code looks fine. There's no issue with using TransactionSychronizationManager, ultimately, it's just synchronizes thread binding of this and other resources...
    Colin Sampaleanu
    SpringSource - http://www.springsource.com

Similar Threads

  1. OpenSessionInView and portlet support
    By garpinc2 in forum Web Flow
    Replies: 31
    Last Post: Apr 9th, 2010, 11:12 AM
  2. Loosing my SecureContext
    By sklakken in forum Security
    Replies: 3
    Last Post: Jul 21st, 2005, 01:44 PM
  3. Replies: 3
    Last Post: May 16th, 2005, 07:04 AM
  4. Replies: 3
    Last Post: Nov 19th, 2004, 07:16 PM
  5. Replies: 9
    Last Post: Sep 25th, 2004, 12:35 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •