2015/03/06

Use JDBC, Spring transactions and @Transactional

Ever wanted to use spring declarative transaction management with a different UI technology than Spring MVC and found out it does not behave really transactional?

There is a good discussion in stackoverflow Spring transaction internals. This describes how spring expects the transactions to behave. I faced a problem when using Spring declarative transactions with Vaadin UI framework which is described more detailed in stackoverflow. The issue I faced was even though I used @Transactional(propagation = Propagation.PROPAGATION_REQUIRED) in my service methods, when those methods are called from a single method in UI, spring treats each of these calls as different transactions and commits the transaction at the end of each service method. The expected behavior was if service methods, methodA(), methodB() and methodC() is called from a caller() method located in UI, those three methods to participate in a single transaction and caller operation to be an atomic operation.

After investigating the issue closely the reason was, Spring will make the methodA(), methodB() and methodC() participate in a single transaction only if a transaction is already started when calling the first service method which is annotated with @Transactional. If this requirement is not met, then the transaction proxy who calls the methodA() will create a transaction. But this transaction will end after executing methodA() and a new transaction is created by the proxy for executing the methodB() and so on. This leads to the behavior of committing after each method call.

So if we can start a transaction before the caller() method in UI kicks in, then Spring transaction proxy will make the methodA() participate in that transaction, and methodB() and methodC(). In this case lets assume if the methodC() is annotated with @Transactional and the propagation setting is PROPAGATION_REQUIRESNEW, the proxy will create a new transaction. This is the expected behavior.

So in SpringMVC and hibernate environment this is done using an OpenSessionInViewFilter which starts a hibernate session in each http request and commits or rollback that transaction at the end of that request. A similar strategy can also be used in our problem. Simply start a transaction in each request and commit or rollback it at the end of the request. This way a dummy transaction is always available when service methods are called and then Spring will nicely manage to participate, create further new transactions or not support the transactions.

A sample servlet filter I came up with is listed below
What this does is get the default transaction manager and starts a new transaction and commit the transaction at the end of the filter chain. As this filter uses spring transaction libraries, the filter should be registered with org.springframework.web.filter.DelegatingFilterProxy as below. Then define a bean in spring context.xml that points to the filter class as below. Now all set except for the fact that it creates a transaction per request as well as a database connection per request. This can be improved and it will be discussed in the next post.

EDIT: Lazy creation of database connections

1 comment:

  1. Hi,

    Thanks for the article and the explanation, but I would like to ask you mentioned if in Spring we use any other UI Controller only then we have to add a filter to use 1 transaction per request. Can you please the reason for this behavior or at least how did you concluded that if we use spring ui controller we won't face this behavior?

    ReplyDelete