Migration from Hibernate 3.6 to 5.4 broke session management?!

Hi Guys,

I have a legacy app that used Spring 4.3 with Hibernate 3.6 which I migrated to Spring 5.3 and Hibernate 5.4. I have this piece of code in a abstract ComonHibernateDAOImpl which is extended in every DAO class I have and serves some common Hibernate tasks.

public abstract class CommonHibernateDAOImpl<ENTITY extends Serializable> extends HibernateDaoSupport implements CommonHibernateDAO<ENTITY> {


  @Override
  public final List<ENTITY> findAll(final Class<ENTITY> entityClass) {
    return getHibernateTemplate().loadAll(entityClass);
  }
}

While this code worked perfectly fine in Hibernate 3.6, is stops working in 5.4 with following error:

Caused by: org.springframework.orm.hibernate5.HibernateSystemException: Calling method 'createCriteria' is not valid without an active transaction (Current status: NOT_ACTIVE); nested exception is org.hibernate.HibernateException: Calling method 'createCriteria' is not valid without an active transaction (Current status: NOT_ACTIVE)
        at deployment.myApp.war//org.springframework.orm.hibernate5.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:267)
        at deployment.myApp.war//org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:370)
        at deployment.myApp.war//org.springframework.orm.hibernate5.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:334)
        at deployment.myApp.war//org.springframework.orm.hibernate5.HibernateTemplate.loadAll(HibernateTemplate.java:519)
        at deployment.myApp.war//com.anes.ilogic.common.integration.dao.impl.CommonHibernateDAOImpl.findAll(CommonHibernateDAOImpl.java:233)
        at deployment.myApp.war//com.cl.ilogic.core.vs.service.VsValidationServiceImpl.reload(VsValidationServiceImpl.java:245)
        at deployment.myApp.war//com.cl.ilogic.core.vs.service.VsValidationServiceImpl.init(VsValidationServiceImpl.java:298)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1930)
        at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1872)
        at deployment.myApp.war//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
        ... 83 more
Caused by: org.hibernate.HibernateException: Calling method 'createCriteria' is not valid without an active transaction (Current status: NOT_ACTIVE)
        at deployment.myApp.war//org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:347)
        at deployment.myApp.war/jdk.proxy21/jdk.proxy21.$Proxy213.createCriteria(Unknown Source)
        at deployment.myApp.war//org.springframework.orm.hibernate5.HibernateTemplate.lambda$loadAll$4(HibernateTemplate.java:520)
        at deployment.myApp.war//org.springframework.orm.hibernate5.HibernateTemplate.doExecute(HibernateTemplate.java:367)
        ... 95 more

If this worked before, then it is because your Spring environment was different previously. As far as I can tell from the Git history, the SessionFactory.currentSession(), which is used by HibernateTemplate, always required that a transaction is running to execute queries. Now, HibernateTemplate seems to have a fallback, where it opens and closes a session when there is no currentSession available.

So my guess is, the new Spring version somehow configures hibernate.current_session_context_class to thread which it didn’t do before.

Yes, I have in fact added this setting during the course of the migration because I thought this would solve my error, which was there before. But even without that flag, the same error comes up. But it appears to me that this is more of a Spring problem than a Hibernate issue.

Check if Spring configures this setting somehow and whether you can disable this.

1 Like

I found the error, it was indeed a Spring misconfiguration. Thank you!

@d00d How did you manage to solve it? Currently facing the same issue after attempted to upgrade to Hibernate 5.4 and Spring 5.

First and foremost, I had to add <tx:annotation-driven /> to my servlet-context.xml configuration file to enable Spring’s built-in transaction management. As a 2nd step, I had to annotate every service class or method that accesses data through a DAO with @Transactional to tell Spring that this DB access should be conducted within a Spring managed transaction. That’s the two steps that were for whatever reason, not necessary in Spring 4.3 with Hibernate 3.6.

Next you have to make sure that in your DAO you acquire an open session. There are two ways to go: you can use sessionFactory.openSession(), which will provide you with a session without automatic transaction management. That means, you have to make sure to begin transaction, commit your work and if necessary handle rollback in case of errors. That will look something like this:

final Session session = this.getSession();
        Transaction tx = null;

        try {
            tx = session.beginTransaction();       
			session.saveOrUpdate(object);              
            tx.commit();		
        } catch (HibernateException e) {
            if (tx != null) {
                tx.rollback();
            }
            log.error("Error occurred during update", e);
        } finally {
            if (session != null && session.isOpen()) {
				session.close();
			}
        }

Second option is to use sessionFactory.getCurrentSession() which is the replacement of Spring 4.3’s obsolete (and removed) SessionFactory.currentSession(). In old Spring 4.x, the currentSession() method was that wonder method that took care about transaction management without necessity to annotate services @Transactional or add the <tx:annotation-driven /> in configuration.

1 Like

Thanks, it is working now except for code that made use of HibernateTemplate. Did you face that issue as well?

HibernateTemplate is working fine for me. Try to declare a bean for HT:

<bean id="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
		<constructor-arg name="sessionFactory" ref="sessionFactory"/>
	</bean>

Thanks a lot. I’ve got it working!