About Koen Serneels

Koen Serneels is a Senior JAVA software engineer with several IBM, Cisco, and Oracle certifications. For more than 10 years he has developed enterprise solutions using Java(EE), Spring, Spring MVC, Web Flow, JSF, and Hibernate. He is co-author of the book on "Pro Spring MVC with Web Flow" by Apress.

Migrating from Hibernate 3 to 4 with Spring integration

This week it was time to upgrade our code base to the latest Hibernate 4.x. We postponed our migration (still being on Hibernate 3.3) since the newer maintenance releases of the 3.x branch required some API changes which were apparently still in flux. An example is the UserType API which was still showing flaws and was going to be finalized in Hibernate 4. The migration went quite smooth. Adapting the UserType’s to the new interface was pretty straightforward. There were some hick ups here and there but nothing painful.

The thing to watch out for is the Spring integration. If you have been using Spring with Hibernate before, you will be using the LocalSessionFactoryBean (or AnnotationSessionFactoryBean) for creating the SessionFactory. For hibernate 4
 
there is a separate one in its own package: org.springframework.orm. hibernate4 instead of org.springframework.orm. hibernate3. The LocalSessionFactoryBean from the hibernate 4 package will do for both mapping files as well as annotated entities, so you only need one for both flavors.

When the upgrade was done, all our tests were running and the applications were also running fine on Tomcat using the local Hibernate transaction manager. However when running on Glassfish using JTA transactions (and Spring’s JtaTransactionManager) we got the ‘No Session found for current thread’ when calling sessionFactory.getCurrentSession();

So it seemed I missed something in relation with the JTA configuration. As you normally do with the Spring-Hibernate integration, you let Spring drive the transactions. You specify a transaction manager and Spring makes sure all resources are registered with the transaction manager and eventually call commit or rollback. Spring will integrate with Hibernate, so it makes sure the session is flushed before a transaction commit.

When using hibernate 3 and the hibernate 3 Spring integration, the session is bound to a thread local. This technique allow you to use the sessionFactory.getCurrentSession() to obtain a open session anywhere inside the active transaction. This is both the case for the local HibernateTransactionManager as for the JtaTransactionManager. However, as of the hibernate 4 integration, the hibernate session will be bound to the currently running JTA transaction instead.

From a user point of view nothing changes as sessionFactory.getCurrentSession() will still do its job. But when running JTA this means that Hibernate must be able to lookup the transaction manager to able to register the session with the currently running transaction. This is new if you are coming from Hibernate 3 with Spring, in fact, you did not have to configure anything in regards to transactions in your Hibernate SessionFactory (or LocalSessionFactoryBean) configuration. As it turned out, with the Hibernate 4 Spring integration the transaction manager lookup configuration is effectively done by hibernate and not by Spring’s LocalSessionFactoryBean. The solution was pretty simple; adding this to the Hibernate (LocalSessionFactoryBean) configuration solved our problems:

<prop key="hibernate.transaction.jta.platform">
org.hibernate.service.jta.platform.internal.SunOneJtaPlatform
</prop>

‘SunOneJtaPlatform’ should then be replaced by a subclass that reflects your container.

See the API docs for the available subclasses. What this class does is actually telling Hibernate how it can lookup the transaction manager for your environment. If you don’t configure this there will be nothing for Hibernate to bind the session to hence throwing the exception. There is also a property:

hibernate.current_session_context_class

Which should point to org.springframework.orm.hibernate4.SpringSessionContext, but this automatically done by the LocalSessionFactoryBean, so there is no need to specify it in the configuration.

As this solved my ‘No Session found for current thread’ problem, there was still another one. Changes made to the database inside a transaction were not visible after a successful transaction commit. After some research I found out that no one was calling session.flush(). While with the hibernate 3 integration there was a SpringSessionSynchronization registered which would call session.flush() prior transaction commit (in the beforeCommmit method).

In the hibernate 4 integration there is a SpringFlushSynchronization registered, which, as its name says, will perform a flush also. However, this is only implemented in the actual “flush” method of the TransactionSynchronization, and this method gets never called.

I raised an issue for this on Spring bugtracker, including two sample application which illustrates the problem clearly. The first uses Hibernate 3 and the other is the exact same application but this time using hibernte 4. The second will show that no information is actually persisted to database (both apps are tested under the latest Glassfish 3.1.2) Until now the best workaround seems to be creating a flushing Aspect that wraps around @Transactional annotations. Using the order attribute you can order the transactional annotation to be applied before your flushing Aspect. This way your Aspect is still running inside the transaction, and is able to flush the session. It can obtain the session the normal way by injecting the SessionFactory (one way or the other) and then calling sessionFactory.getCurrentSession().flush().

<tx:annotation-driven order="1">
 
<bean id="flushinAspect" clas="...">
 <property name="order" value="2">
</property></bean>
</tx:annotation-driven>

or, if using the annotation configuration:

@EnableTransactionManagement(order=1)

Update:

There was some feedback on the issue. As it turns out it does not seem to be a bug in the Spring Hibernate integration, but a missing Hibernate configuration element. Apparently the ‘hibernate.transaction.factory_class’ needs to be set to JTA, the default is JDBC which depends on the Hibernate Transaction API for explicit transaction management. By setting this to JTA the necessary synchronizations are registered by hibernate which will perform the flush. See the Spring
https://jira.springsource.org/browse/SPR-9404

Update 2:

As it turns out, after correcting the configuration as proposed on the preceding issue, there was still a problem. I’m not going to repeat everything, you can find detailed information in the second bug entry I submitted here: https://jira.springsource.org/browse/SPR-9480 It basically comes down to the fact that in a JTA scenario with the JtaTransactionFactory configured, hibernate does not detect that it is in a transaction and will therefore not execute intermediate flushes. With the JtaTransactionFactory configured, you are expected to control the transaction via the Hibernate API rather then via an external (Spring in our case) mechanism. One of the side effects is that you might be reading stale data in some cases.

Example:

//[START TX1]
Query query = session.createQuery('from Person p where p.firstName = :firstName and p.lastName = :lastName');
Person johnDoe = (Person)query.setString('firstName','john').setString('lastName','doe').uniqueResult();
johnDoe.setFirstName('Jim');
Person jimDoe = (Person)query.setString('firstName','jim').setString('lastName','doe').uniqueResult();
//[END TX1]

What happens is that when performing the second query at line 5, hibernate should detect that it should flush the previous update which was made to the attached entity on line 4 (updating the name from ‘john’ to ‘jim’). However, because hibernate is not aware it is running inside an active transaction, the intermediate flushing doesn’t work. It will only flush once before the transaction commits. This results in stale data, as the 2nd query would not find ‘jim’ and return null instead. The solution (see the reply from Juergen Hoeller in the issue) is configuring hibernate.transaction.factory_class to org.hibernate.transaction.CMTTransactionFactory instead. At first I was a bit sceptical, as CMT makes be thing about EJB containers. However, if you read the Java doc on CMTTransaction it does make sense:

/**
 * Implements a transaction strategy for Container Managed Transaction (CMT) scenarios.  All work is done in
 * the context of the container managed transaction.
 *
 * The term 'CMT' is potentially misleading; the pertinent point simply being that the transactions are being
 * managed by something other than the Hibernate transaction mechanism.
 *
 * Additionally, this strategy does *not* attempt to access or use the {@link javax.transaction.UserTransaction} since
 * in the actual case CMT access to the {@link javax.transaction.UserTransaction} is explicitly disallowed.  Instead
 * we use the JTA {@link javax.transaction.Transaction} object obtained from the {@link TransactionManager}

After that everything seems to work fine. So to conclude, if you want hibernate to manage the JTA transaction via the UserTransaction, you should use JtaTransactionFactory. In that case you must use the Hibernate API to control the transaction. If there is someone else managing the transaction (Spring, EJB container …) you should use CMTTransactionFactory instead. Hibernate will then revert to registering synchronisations, by checking for active javax.transaction.Transaction using the javax.transaction.TransactionManager. If there is any other issue popping up I’ll update this entry accordingly.
 

Reference: Migrating from Hibernate 3 to 4 with Spring integration from our JCG partner Koen Serneels at the Koen Serneels – Technology blog blog.

Related Whitepaper:

Functional Programming in Java: Harnessing the Power of Java 8 Lambda Expressions

Get ready to program in a whole new way!

Functional Programming in Java will help you quickly get on top of the new, essential Java 8 language features and the functional style that will change and improve your code. This short, targeted book will help you make the paradigm shift from the old imperative way to a less error-prone, more elegant, and concise coding style that’s also a breeze to parallelize. You’ll explore the syntax and semantics of lambda expressions, method and constructor references, and functional interfaces. You’ll design and write applications better using the new standards in Java 8 and the JDK.

Get it Now!  

Leave a Reply


four × = 4



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

15,153 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books