Nerd Notes

/dev/brain: no space left on device

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

25 Responses

Subscribe to comments with RSS.

  1. This is a good post. It really helps me to understand transaction capability of spring.

    Shoeb

    January 5, 2008 at 8:05 am

  2. First of great article, I had a quick question. If I do all of this and I have one method in my DAO and it updates two tables in the same database, would they both get rolled back if I have threw a checked exception when one inserted data?

    syed

    June 21, 2008 at 9:51 am

  3. If the exception gets thrown inside the DAO method, the framework should take care of rolling back the whole transaction.

    Mirko Caserta

    June 22, 2008 at 8:17 am

  4. Thank you very much for this informative article!

    techzen

    June 23, 2008 at 9:52 pm

  5. Thanks very much for posting very good article. Please extend this to some other features of the Spring.

    Jhonjk

    August 8, 2008 at 9:02 am

  6. Thank you very much for posting such a good article.

    Vinita

    November 6, 2008 at 10:30 am

  7. My Dao has two insert queries and one select query. I want to use one transaction for this but I don’t see rollback if somthing goes wrong with one of the inserts. Hier is my config file



    PROPAGATION_REQUIRED,-Exception
    PROPAGATION_SUPPORTS

    What can be wrong here?
    Thanks in adavance
    Slobodanka

    Slobodanka

    November 10, 2008 at 1:44 pm

  8. How can I attach my cpring-config file?

    Slobodanka

    November 10, 2008 at 1:46 pm

  9. Nice job !

    Goulven

    December 8, 2008 at 2:26 pm

  10. […] are a couple of really good and concise tutorials on how to set up transactions in Spring: https://nerdnotes.wordpress.com/2007/03/30/basic-transactions-in-spring-using-transactionproxyfactory… […]

  11. Very good article to understand concepts clearly

    Sanjay Bhardwaj

    February 18, 2009 at 6:37 am

  12. Hi Dude,

    Finally I landed to the place where I understood how transaction works.

    Thanks for this post

    Amit

    March 10, 2009 at 8:40 am

  13. Hi,

    Thanks for the article.
    A very fundamental question in Spring:
    Ur example talks of a standalone app..for which I presume u have driver class with main() to load the appCntxt. That wld mean its a run-and-die kinda app..Is that the duration when the spring context is alive? Meaning if I were to keep the sprint context alive beyond just the main(), do I need to crank up a RMI registry using Spring remoting? or is there a better way? Also was wondering wat one means by a Spring “Container” and wld that help?

    Thanks.

    Sourav

    August 12, 2009 at 4:15 pm

  14. This is annoying me. Not your tutorial, but the fact that it did not solve my actual problem. I have an interface to my application, and an implementation of it. This implementation is the target class for for the transaction interceptor. But when I load my web app, I get an error stating that there is no single bean that implements my interface, but two: the transaction interceptor and my implementation.

    I am A) doing something wrong or B) doing something seriously wrong.

    In my case I need to autowire an implementation into several controllers. It doesnt work when I try to declare a transaction interceptor. Any idea?

    Jarl André

    August 12, 2009 at 6:10 pm

  15. As with all questions asked by a n00b, they are usually not relevant :P

    I used pointcut and advisor with aspectweaver and all that to configure my business logic transactional totally external from the code. And yes, it worked like a charm! Keep up the good work writing tuts!

    Jarl André

    August 15, 2009 at 10:15 am

  16. I see you can configure transaction with AOP, advisor, pointcut and with TransactionProxyFactoryBean. Are they two different approaches or they work together?

    Maggie

    August 19, 2009 at 1:27 pm

  17. This might not be too smart of me if I put my solution into this discussion because it is taken straight out of Spring documentation. But I believe that documentations sometimes can be deadly boring to read, so here is my solution to transactions:

    I dont know how to answer your question, but one thing: my solution looks a lot more cleaner. Less xml, less trouble to read.

    Jarl André

    August 19, 2009 at 1:34 pm

  18. Jarl André

    August 19, 2009 at 1:35 pm

  19. the code didn’t go through .. hacking my way in one more time:

    <tx:advice id=”txAdvice” transaction-manager=”txManager”>
    <tx:attributes>
    <tx:method name=”get*” read-only=”true” />
    <tx:method name=”*” />
    </tx:attributes>
    </tx:advice>

    <aop:config>
    <aop:pointcut id=”serviceExecution” expression=”execution(* some.business.intferfaces.*.*(..))” />
    <aop:advisor advice-ref=”txAdvice” pointcut-ref=”serviceExecution” />
    </aop:config>

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

    Jarl André

    August 19, 2009 at 1:40 pm

  20. Thanks for a concise post on this topic.

    We developed a standalone program taking similar approach. My understanding of this approach is that each call to a method of the wrapped class is defined as one transaction. My question is around the autocommit property in the connection used by the datasource. By default, it is set to true, i.e., a commit statement will be issued for each sql statement in a method. It conflicts with my understanding of the approach set up in your post. Does the set up take care of this by setting the autocommit property to false?

    I tried googling for the answer, but couldn’t find any.

    Thanks!

    Feng Yang

    October 8, 2009 at 6:23 pm

  21. Hi this is a nice doc but how can i use taget of foorBarService.

    Tanu

    January 6, 2010 at 10:56 am

  22. hi ,
    I have a question how to get hold of the injected transaction object in the fooBarServiceImpl. This would be necessary if you want to control transactions
    by your self…
    is it possible

    prasamma

    January 7, 2010 at 7:46 am

    • nice doc,gives an idea about transaction.show with some sample example

      jadeja

      May 19, 2010 at 11:09 am

  23. Hi
    please tell me what r the jar files needed for this example

    vish

    August 29, 2011 at 4:16 am

  24. Reblogged this on devmaany.

    maany

    August 9, 2015 at 9:01 am


Leave a reply to Jhonjk Cancel reply