On Hibernate, Spring, Sessions and Transactions
I was recently working with Spring and Hibernate on a pet project and ran into some issues with Session and Transaction management that proved to be pretty interesting in the end. The following assumes a working knowledge of Hibernate and Spring…
I was in the midst of writing some JUnit 4.x tests using SpringJUnit4ClassRunner
and the @TransactionalConfiguration
/ @Transactional
annotations for automatic rollback of @Test
methods. I wanted to do some manipulation of the database prior to my tests using a separate method annotated with @Before
. What I was reminded of very quickly is that Spring’s class runner will not apply a transactional aspect to this method since it’s not actually a @Test
. This isn’t a problem if you are using HibernateTemplate
/ HibernateCallback
, since it ultimately has a reference back to your TransactionManager
to handle transactions. But if you want to work with the raw Hibernate APIs it can be problematic.
There are two things to keep in mind: (1) SessionFactory.getCurrentSession()
will only work if you have configured the SessionFactory
appropriately, and (2) depending on the configuration, you may have to manage Transactions
explicitly. The configuration property in question is hibernate.current_session_context_class
and it is commonly configured one of three different ways:
1. Omitted the property from the configuration
Hibernate will throw an exception on calls to getCurrentSession()
complaining that there is no CurrentSessionContext
configured.
2. Configured with ‘thread’
hibernate.current_session_context_class=thread
Hibernate will bind the Session returned from getCurrentSession()
to the current thread and you must manage transactions programmatically. Generally all that’s required is to call Session.beginTransaction()
. You can also invoke Transaction.commit()
or rollback()
if you wish.
3. Configured with SpringSessionContext
hibernate.current_session_context_class=org.springframework.orm.hibernate3.SpringSessionContext
Hibernate will assume it is executing inside of a Spring transactional context (i.e. through a Spring transactional aspect) and Spring will now manage your transaction for you. However if you call getCurrentSession()
outside of such a context, Hibernate will throw an exception complaining that no Session is bound to the thread.
What does all this mean?
- Use
SpringSessionContext
if your operations will be done through classes that are invoked through a Spring-managed transactional context or if you can introduceHibernateTemplate
and/orHibernateCallback
wherever you need it. - Use “thread” if you need to raw with the raw Hibernate Session/Transaction API and remember that you’ll need to manage transactions programmatically.