Configuring Hibernate and Spring for JTA

Maarten Winkels

Spring is a great framework for dependency injection and it comes with a lot of support classes and utilities for all kind of things. Hibernate is a persistence service with a lot of useful features, that is relatively easy to use. Configuring both frameworks is not always easy. Configuring them together is sometimes hard and it is easy to make mistakes.

This blog addresses a problem in a configuration that is fairly common: use Spring for transaction management on top of a JTA provider and use Hibernate for persistence. Transaction demarcation is easy and declarative with Spring. The problem is that Hibernate sometimes needs to detect the current transaction and this needs to be configured. This leads to hard to detect bugs in applications that rely on auto flushing.

Auto Flushing
Auto flushing is a Hibernate feature which will synchronize in-memory state with database state when a query is executed. Normally, Hibernate will only synchronize in-memory and database state when the session is flushed. With Spring this can be configured to occur when the transaction is committed. This might lead to unexpected behaviour. Look at the code below

  public void transactionInterceptedMethod() {
    Person p = new Person("Maarten");
    personDao.save(p);
    List persons = personDao.findAll();
  }

Will the new person be in the list of persons? I think everybody would suspect so. In fact, this relies heavily on how Spring and Hibernate are configured.

  1. The person object will not immediately be inserted into the database when offered to Hibernate. It will be kept in memory, until the session is flushed. (There are exceptions, but this is the general rule).
  2. The findAll method will look in the database in the same transaction as the one that is used to insert the person object. Still it will only find the new person if it has been inserted into the database in the same transaction before the query is made.
  3. Spring will commit the transaction and instruct Hibernate to flush the current session only at the end of the method.

All these circumstances influence the result of the findAll method. It seems that we can only have the new person object in the list if we flush the session between the save and findAll methods.

This is where auto flushing comes in. When the flush mode of the session is set to "AUTO", Hibernate will inspect the in-memory state to see if there are any changes that might influence the result of any query that it is about to execute. If Hibernate determines this is so, it will flush the session, synchronizing the in-memory state and the database state. This will not alter the transactional status, but inly execute some SQL statements within the current transactional context.

Auto-flushing is quite intelligent in what to flush when, although some situations might be hard to detect. To improve performance, Hibernate will not simply always flush everything, but look at the tables in the database that the query touches and the data in-memory that should be stored in those tables. If there is no overlap, no data will be persisted. If an overlap is found, the whole session will be flushed, to ensure consistency.

Spring, JTA and transaction detection
Now this all seems to work out fine, but what does it have to do with Spring, JTA or transaction detection? Well, Hibernate will only perform auto flushing if it detects that there is a transaction running. It is not completely clear to me why it won't do the flushing, but this is how it works. It has a number of strategies for detecting that there is a transaction. The default strategy is to look at its own transaction mechanism.

When using Spring, to manage transactions, using Hibernates mechanism for transactions (which is a thin layer on top of JDBC) is an option. This mechanism does not support distributed transactions. To support distributed transactions, Spring says you can just drop in their JtaTransactionManager to replace the HibernateTransactionManager. This is not completely true though: It will work seamlessly for transaction demarcation, but not for transaction detection through hibernate.

Transaction demarcation will work fine: Spring will start a new Hibernate session whenever a transaction is started. Hibernate will work with that session, oblivious of the transaction that has been opened. This is not a problem for demarcation: Spring will flush and close the session when the transaction is closed.

For Hibernates transaction detection it does not work: Hibernate is oblivious to the Spring started transaction and it will not do auto flushing. There are not many features in Hibernate that depend upon transaction detection, so this misbehavior of the system might go undetected for quite a while. The problem with auto flushing is that it is not always as simple as two consecutive lines doing a save and findAll. The logic that saves an entity and the logic that depends upon the entity being found by a query within the same transaction might be in separate classes, only connected by a typical flow.

Solution
So how do we tell Hibernate what strategy to use for transaction detection? There are two possibilities: 1) configure Hibernate directly or 2) configure Hibernate through Spring.

To configure Hibernate directly, use the hibernate.transaction.manager_lookup_class and hibernate.transaction.factory_class. These properties would be used by Hibernate to start transactions, but we're not starting transactions through Hibernate, just detecting them.

To configure Hibernate through Spring, inject a JtaTransactionManager into the LocalSessionFactoryBean. Depending on the specific version of Spring you are using, additional settings must be changed.

Conclusion
Developing with powerful frameworks like Spring and Hibernate makes many tasks easy. It is of great importance that the frameworks are correctly configured, especially if they need to work together. I hope blog will help you detect a particular small bug in your configuration, that could lead to severe problems.

Comments (6)

  1. domenico - Reply

    August 10, 2008 at 11:21 am

    i'm actually facing this kind of problems with an ejb3 application wich use spring 2.5, hibernate and container provided jta support. The app is deployed on glassfish v2. My biggest problem is with transaction demarcation and propagation between the service layer and the repository layer where i need to annotate all methods with @transactional annotations and call entitymanager.flush() to let hibernate commit changes on the model. Still i'm facing some strange behaviours like the one that you describe. I would like to know where i can find some example for such configuration.
    Best regards

  2. Klaas van der Ploeg - Reply

    August 27, 2008 at 11:30 am

    "It is not completely clear to me why it won't do the flushing"

    If there is no transaction than flushing would mean starting a JDBC transaction, inserting records, committing and thereby essentially breaking the isolation of the current session. Records will be in the database possibly to be deleted from other transactions. This is fundamental in guaranteeing consistency between transactions.

  3. James - Reply

    November 11, 2009 at 9:13 am

    It would be great, if you can explain with some code samples. That will help the readers to understand the problem better.

  4. Bill - Reply

    February 14, 2010 at 1:17 am

    This article is useless and is yet another example how much garbage is on the internet. With how finicky it is to use Spring and Hibernate what's the point of describing something without any examples of what you are talking about?

  5. md - Reply

    November 13, 2010 at 11:05 am

    We are using EJB 2.1 in websphere . Hibernate core is used as ORM for persistence layer. After 2 years of working we are facing issues
    1. record saved in same transaction is not found later in the same transaction scope.
    2. data in all tables involved in a transaction is not inserted/updated. We checked at db2 layer. It doesn't show SQL for missing entries.

    We are using auto-flush and auto-close feature of hibernate. This issue has come when websphere server was going down.

  6. Maciek - Reply

    March 26, 2011 at 6:22 pm

    To Bill,

    Please read the article 2, 3 or more times. Than read this documentation: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/orm/hibernate/LocalSessionFactoryBean.html. Maybe some day you will see the big picture.

    Great article!

Add a Comment