Thursday, May 22, 2008

Spring Can Hide Transaction Demarcation Failures

When you define a TransactionProxyFactoryBean containing TransactionAttributes, the method names you use for transactional boundaries need not exist. The transaction attributes are examined to determine which methods on the inner class need to have advice applied, but nothing prevents you from attempting to apply transactions on methods that do not exist.

That sounds pretty innocuous, but it can mean that you thought you applied a transaction to a service method, but failed to do so, or that a service method that was renamed is no longer transactional but that you receive no warning. This has bitten me a few times, and I've seen very little discussion of it, so I thought I'd record it here.

This is of particular import if the underlying persistence implementation (ORM and Database) are willing and able to create transactions for you, or operate non-transactionally, if you fail to do so yourself. Without this, service methods that don't have a transaction boundary will simply error out when they attempt to do any serious work with the underlying database. With these "simplifying" assumptions, your service methods may be written as if they are transactional, but without the safety applied by having a transactional boundary.

With this in mind, I lean towards using the @Transactional annotation that Spring provides, which is more visible when you're doing work in the service class and less likely to get lost during simple refactorings.

Alternately, if you're using Spring and Hibernate, you might want to turn off HibernateTemplate's allowCreate, which enables it to create a session if not present, which helps to mask the problem.

I hope this saves some of you future pain.

No comments: