Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Upgrading to Hibernate 4.1 and the "infamous" HibernateTemplate

Tags:

I'm upgrading our project from Hibernate 3.0 to Hibernate 4.1.6. (And we are currently using spring 3.1)

I read in many articles and in HibernateTemplate documentation, that since version 4.0 HibernateTemplate is not supported and that I should replace it's usage with calling sessionFactory.getCurrentSession() to get a session.

Since this project was started with older version of Hibernate, where the use of HibernateTemplate was encouraged, we currently have 124 usages of HibernateTemplate across our project. I'm afraid that replacing all these occurrences with sessionFactory.getCurrentSession() might insert regression bugs in our project. In addition, there are some places where HibernateTemplate was used in a non-transactional context, where there is no 'current' session. What should I do in those cases? Open a new session and handle (close) it myself? That wasn't the case when I used HibernateTemplate.

Do you have some good strategy addressing these issues?

Thanks.

Relevant reading:

  1. Hibernate Vs. Spring - HibernateTemplate history
  2. Hibernate Core Migration Guide
  3. MIGRATING TO SPRING 3.1 AND HIBERNATE 4.1
  4. org.springframework.orm.hibernate3.HibernateTemplate
like image 490
Ido.Co Avatar asked Aug 28 '12 11:08

Ido.Co


2 Answers

Okay, So this is what I actually did, I don't know if this is the best solution for this problem, but under our circumstances, and since I was looking for the most localized solution, it seemed best to me.

I have extended the springframework.orm.hibernate3.HibernateTemplate and created a new MyHibernateTemplate. The new template's main role is to override the doExecute method that most of the hibernate3.HibernateTemplate eventually lead to, and also supply some of the functionality that was provided by the old SessionFactoryUtils (like isSessionTransactional and applyTransactionTimeout).

The new doExecute replicates the logic of the old one, but instead of SessionFactoryUtils.getNewSession to get a session it first try to look for an open session getSessionFactory().getCurrentSession() :

boolean newSessionOpened = false;
Session session;

if (enforceNewSession){
    session = SessionFactoryUtils.openSession(getSessionFactory());
    newSessionOpened = true;
} else {
    try {
        // look for an open session
        session = getSessionFactory().getCurrentSession();
    }
    catch (HibernateException ex) {
        try {
            // if there isn't an open session, open one yourself
            session = getSessionFactory().openSession();
            newSessionOpened = true;
        } catch (HibernateException e) {
            throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
        }
    }
}

// is the open session, is a session in a current transaction?
boolean existingTransaction = (!enforceNewSession &&
        (!isAllowCreate() || isSessionTransactional(session, getSessionFactory())));

You just need to close this session manually:

    finally {
    // if session was used in an existing transaction restore old settings
    if (existingTransaction) {
        //logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
        disableFilters(session);
        if (previousFlushMode != null) {
            session.setFlushMode(previousFlushMode);
        }
    }
    // if not and a new session was opened close it
    else {
        // Never use deferred close for an explicitly new Session.
        if (newSessionOpened) {
            SessionFactoryUtils.closeSession(session);
            //_log.info("Closing opened Hibernate session");
        }
    }

I'm Trying keep this answer short, but if there are any questions I can elaborate further about this problem.

like image 78
Ido.Co Avatar answered Sep 22 '22 04:09

Ido.Co


Check out this section in the docs. It says that SessionFactory.getCurrentSession() is pluggable and there is a ThreadLocalSessionContext implementation that keeps the 'current session' in the ThreadLocal rather than a JTA transaction. ThreadLocalSessionContext will also close the Session at the end of the hibernate Transaction created from that Session, so you don't have to worry about closing the Session yourself.

With regards to introducing regression bugs, upgrading a library will always have it's risks, especially so when it is something as core to your application as hibernate. The only advice I can give is to ensure your test suite has decent coverage before the upgrade. After all, that's the job of your test suite - to catch regression bugs.

like image 31
theon Avatar answered Sep 20 '22 04:09

theon