del.icio.us Digg DZone Reddit StumbleUpon
Annotation-Based Transactions in Spring - Willie Wheeler
« Previous | 1 | 2 | 3

Annotating the Java Interface

With Spring, you typically apply transaction annotations either to Java interfaces for service beans, or else to the service beans themselves. If you apply the annotations to the interfaces then the transaction definition holds true for any classes implementing those interfaces. We'll do that here, but remember that you can apply the annotations to the service beans themselves as well.

Here's an interface for a simple article service. This service allows the application to get an article by ID, and also to post a comment for a given article.

package myapp.service;

import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import myapp.model.Article;
import myapp.model.Comment;

@Transactional(
    propagation = Propagation.REQUIRED,
    isolation = Isolation.DEFAULT,
    readOnly = true)
public interface ArticleService {
    
    Article getArticle(long articleId);
    
    @Transactional(readOnly = false)
    void postComment(long articleId, Comment comment);
}

The first thing to notice is again just how ridiculously simple this is. I probably don't need to explain it but I will anyway just to be safe. The @Transactional annotation we define on the interface is setting default values for the various methods that form the interface. So we are saying here that unless the method itself specifies otherwise, we want Propagation.REQUIRED for the propagation behavior, we want the default isolation level, and we want to flag methods as read-only.

The only other piece to mention is that I've overridden the readOnly setting for the postComment method since that's obviously a write method.

If it could be any simpler I'm not sure how. Now let's look at the Spring configuration file.

The Spring Configuration File

Here it is:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-2.5.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
    
    <!-- Wire beans here -->
    ...

    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        ...
    </bean>
    
    <!-- This tells Spring to activate annotation-driven transactions -->
    <tx:annotation-driven/>
</beans>

That's it—really! Make sure you include both the aop and tx namespaces and schema locations since that's where the magic lives. You have to wire your beans up just like you normally would (though note that you can even use annotations to autowire your beans). And you have to provide a transaction manager of one kind or another. I'm using the Hibernate 3 HibernateTransactionManager but use whatever you want. If you give your transaction manager the id transactionManager, then you can take advantage of a little Spring convention-over-configuration: <tx:annotation-driven> will pick that up automatically. (And if you want to call your transaction manager something else, that's fine too. Just reference that ID using the transaction-manager attribute of the <tx:annotation-driven> element.)

Oh, the <tx:annotation-driven> element just tells Spring that you want it to pick the transaction definitions up from the Java annotations. I'm not sure how it works behind the scenes, but I think Spring will run through the beans in your context and create the necessary transaction aspects. Not positive about that—if you know the details, I'm interested—but in any case you end up with annotation-driven transactions. Nice!

That's all there is. As always let me know if you have comments or questions.

Social bookmarks: del.icio.us Digg DZone Reddit StumbleUpon
« Previous | 1 | 2 | 3

Comments (18)

Nice article!

One thing: You show annotation on interface in your example, but actually, the official recommendation is to put the annotation on the class.

Here is an except from the docs at

http://static.springframework.org/spring/docs/2.0.x/reference/transaction.html

"...The Spring team's recommendation is that you only annotate concrete classes with the @Transactional annotation, as opposed to annotating interfaces. You certainly can place the @Transactional annotation on an interface (or an interface method), but this will only work as you would expect it to if you are using interface-based proxies. The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy (which would be decidedly bad). So please do take the Spring team's advice and only annotate concrete classes (and the methods of concrete classes) with the @Transactional annotation...."
By Tech Per on Mar 18, 2008 at 2:38 AM PDT
Great article Willie. The transaction semantics are changing a little in the 2.5.3 branch in a way that you'll have to update your article soon. Please see the release notes under "Transaction Semantics" shaping up on the spring forum: <a href="http://tinyurl.com/2g9mqh">here</a>
By Lucas Kursof on Mar 18, 2008 at 7:06 AM PDT
@Lucas: :-)

@Tech Per: I moved your comment from the autowiring article to this one because I think that it was meant to go here.

Thanks very much for the nice words and especially for pointing out the problem. I'll update the article accordingly and include an explanation as to what the issue is.
By Willie Wheeler on Mar 18, 2008 at 8:15 PM PDT
Excellent post. Really enjoyed reading your article.

I was hoping to explore Spring's transaction management and had the Spring doc opened for last few days. You just made all that so so simple! :)

Thanks a lot for your effort.
By Asif Iqbal on Mar 18, 2008 at 11:48 PM PDT
Awesome article Willie! Very easy to follow. As you mentioned in the article itself, very simple and easy to understand examples.
I'm pretty new to Spring and still learning it. Your article really helped me to easily go through the Transaction management chapter in the Spring book that I'm following :).
Thank you so much for such a nice article.
By Parthiban Periyasamy on Mar 20, 2008 at 4:39 AM PDT
Really appreciate the feedback. Thanks guys.
By Willie Wheeler on Mar 20, 2008 at 7:08 PM PDT
Wonderful article... Thanks for it
By Kalai on Jun 4, 2008 at 2:21 AM PDT
Really excellent. Thanks for you time and dedication, Willie. It's nice to see that Eclipse (and I'm sure other modern IDEs) will actually offer code completion for the various annotation properties that can be set for @Transactional.

Something curious that I noticed, I had my applicationContext.xml set up with this doctype:

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">

and when I added your
<beans xmlns="http://www.springframework.org/schema/beans"...
inside that doctype and then tried to deploy I got errors saying that something was wrong with the xmlns declaration. I removed the doctype and it works perfectly. I'm new to Spring so I hope I've done the right thing. (if so, I hope this tip helps someone else).
By Paul Schwarz on Jun 17, 2008 at 7:23 AM PDT
Thanks Paul. I'm guessing the problems you ran into are related to the fact that that DTD is for Spring 1.2. (If you pull up the DTD in question you can see the reference to Spring 1.2 in the source.) Your namespace declaration on the beans element takes care of validation for you, using XML schemas instead of the older DTD approach.
By Willie Wheeler on Jun 17, 2008 at 2:33 PM PDT

Very Nice article. Thanks.

By Pradeep Tiwari on Feb 23, 2009 at 2:54 AM PST

Thanks for good article. I have one question : Does spring creates proxy for the classes which are annotated with @Transactional. ?

Is this has something to do with AOP?

Appreciate your reply

Thanks Umesh

By Umesh Gohil on Apr 21, 2009 at 11:50 PM PDT

Hi Umesh,

Yep, that is exactly how it works: with proxies and AOP. The AOP concept really goes hand-in-hand with the whole dependency injection thing. A lot of times people talk about dependency injection in conjunction with testing, but in my opinion an even more powerful application is being able to add decorations (like transactional behavior) to components and that's exactly what's going on here.

Willie

By Willie Wheeler on Apr 22, 2009 at 7:27 AM PDT

Thanks Willie, Appreciate your reply.

So it is safe to assume that underlying Transaction have defined Aspect, Pointcut for the @Transaction annotation.

Regards UmeshGohil

By Umesh Gohil on Apr 22, 2009 at 8:57 AM PDT

Excellent article Umesh!!

By Murty on Jun 17, 2009 at 8:23 PM PDT

Huge thanks Willie. Do you know how to incorporate pre and post interceptors when using annotations for transactions? I'm trying to figure that out.

By Abe Mishler on Dec 22, 2009 at 11:32 AM PST

I found exception when using code above. It said : org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

Please your best suggestion to resolve this issue.

Regards, Rendi

By rendi on Feb 9, 2010 at 7:24 PM PST

Hi Willie,

I am new to Spring and unable to understand the difference between proxy-based vs AOP-based approach. I would really appreciate if you can explain these 2 with sample example and best practices of using this two.

Thanks in advance.

Best Regards - Roy

By Roy on Mar 12, 2010 at 12:06 AM PST

This is excellent post Willi.

I am new to Spring and unable to understand the difference between proxy-based vs AOP-based approach. I would really appreciate if you can explain these 2 with sample example and best practices of using this two.

Thanks in advance. Khush.

By Khush on Jul 27, 2010 at 11:59 PM PDT

Post a comment

Your name:
Your e-mail address (won't be displayed):
Your web site (optional):
example: www.xyz.com
Your comment:
Preview:
By You
Please help us reduce comment spam:
Spring in Practice
My brother and I are writing Spring in Practice for Manning!

What's New?

2009-08-30 - Check out my two-part series on DZone: Spring Integration: A Hands-On Tutorial.
2009-03-25 - My new article Getting Started with Spring Batch 2.0 is available on DZone.
Home | Consulting | Tech Articles | Mailing List | Contact | Spring Blog
Copyright © 2008 Wheeler Software, LLC.