Nerd Notes

/dev/brain: no space left on device

Archive for the ‘transaction’ Category

Basic transactions in Spring using TransactionProxyFactoryBean

with 25 comments

UPDATE – Aug 29, 2011: I see that quite a few sites link to this article. Please keep in mind that I wrote this at the beginning of year 2007. While it should still be valid, more recent versions of the Spring Framework have largely simplified the approach described here and the online documentation about transaction management is far more complete, precise and straightforward than what I wrote years ago. I strongly encourage you to read the Spring documentation for the most up-to-date details.

Scenario: you have a simple stand-alone java application which accesses a single database using spring DAOs and you want to make your application’s interface transaction aware.

Now, while there’s plenty of ways to achieve this, the fool-proof, working approach is to make use of Spring’s declarative transactions and the TransactionProxyFactoryBean.

Here is an example BeanFactory configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd"
>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/foobardb"/>
<property name="username" value="dbuser"/>
<property name="password" value="dbpass"/>
</bean>
<bean id="fooDao"
class="com.acme.backend.dao.FooDAOJdbc">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="fooBarServiceImpl"
class="com.acme.backend.FooBarServiceImpl"/>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="foorBarService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="fooBarServiceImpl"/>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>

Okay, this was a lot of configuration data but, don’t worry, we’ll get into each little bit, one at a time and, by the end of this article, you’ll have all figured out.

In the first part, you basically have a boilerplate xml declaration of the required schemas. Those are needed so that your xml editor knows how to do auto completion and so that, when the xml configuration file gets parsed, the parser knows what is syntactically and semantically correct and what’s not.

Then you have a datasource bean declaration:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/foobardb"/>
<property name="username" value="dbuser"/>
<property name="password" value="dbpass"/>
</bean>

This simply declares a configuration object with the datasource properties, which are the usual driver class name, connection URL and login credentials to the database. If you look closely, you’ll see that I’m using a commons-dbcp BasicDataSource. This means two things:

  1. the connections you’re going to get from this datasource are going to be pooled by the commons-dbcp driver
  2. you’ll have to put the commons-dbcp and commons-pool jars in the classpath

The next piece is quite simple:

<bean id="fooDao"
class="com.acme.backend.dao.FooDAOJdbc">
<property name="dataSource" ref="dataSource"/>
</bean>

This declares a DAO, plugs in a jdbc implementation class for it and injects the datasource as a property of the DAO.

<bean id="fooBarServiceImpl"
class="com.acme.backend.FooBarServiceImpl"/>

This declares the service implementation. In other words, this is the bean that implements the interface to our application. It is here merely because we need to declare a placeholder we’ll use in the transactional proxy declaration later.

<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

Here we have declared a transaction manager using Spring’s default DataSourceTransactionManager. Then, we inject the datasource property into the transaction manager bean so that it becomes aware of what it should operate upon.

<bean id="foorBarService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager" ref="txManager"/>
<property name="target" ref="fooBarServiceImpl"/>
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

This is a bit more complicated and needs some careful explanation. The bean we’re declaring here is a transaction proxy, a class provided by Spring which takes care of wrapping the service implementation with a transactional behavior.

The transaction proxy needs a few properties set. Let’s see what they are:

  • a transaction manager (remember we had declared that earlier, hadn’t we?)
  • a target class; this is the class that the proxy wraps and adds transactional behavior to
  • the transaction attributes

The transaction attributes are a set of properties. They describe what the transactional behavior should be. In this very simple but effective example, we are declaring that all methods of our service interface beginning with the name get are to be considered read-only and that they support transaction propagation. The other methods are considered as write methods in terms of transaction behavior and they require transaction propagation.

Now you’re gonna ask me: “And all of this is for what?”. Well, what you achieve with this kind of configuration is a fully transactional service. That means, if something goes wrong within your service operation, all you have to do is throw an exception and the Spring framework (and your database) will take care of rolling back all work.

For a simple, standalone application, this is just great. With a few lines of xml configuration data, you’ve got a fully transactional service. Ain’t that great? If you think it’s not, then you must take a long walk with an Oracle architect.

Written by Mirko Caserta

March 30, 2007 at 11:09 am