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

Transaction Basics

Feel free to skip this page if you already understand transactions and just want to see how to define transactions in Spring using annotations.

The core idea behind a transaction is that it's a complex operation completed as an all-or-nothing set of simpler operations. If one of the simpler operations fails, then none of the operations should be applied.

The classic example is making a purchase, and indeed this is probably where the name "transaction" comes from. There are several steps:

  1. Pull funds from buyer's account
  2. Add funds to seller's account
  3. Decrease product inventory

A failure could happen at any of those steps. For example, at step 1, if the buyer doesn't have enough money, then the transaction should fail. (We wouldn't add funds to the seller's account and we wouldn't decrease product inventory.) At step 2, if the seller's account has been frozen due to suspected involvement in illegal activities, then the transaction should fail. At step 3, if the product is out of stock, then again the transaction should fail.

That's just the classic example. There are other examples that are transactions in the technical sense even though a non-technical person wouldn't normally regard them as transactions per se. For instance, my web site allows end users to submit comments on articles. I have a database table for comments and a separate link table that links comments to their associated articles. (I have it this way because I want to be able to relate comments to other entities as well.) So to add a comment, I need to insert a record into the comment table and then another record into the link table. If either of those inserts fails, then I don't want to run either one. That's a transaction too, at least in the narrower technical sense that we're discussing here.

I would say that the all-or-nothing nature of transactions is their defining characteristic, but it is generally recognized that there are four major characteristics we have in mind when we call something a transaction. They are the ACID properties.

ACID Properties

ACID is an acronym that stands for atomic, consistent, isolated and durable. An operation is a transaction if and only if it has these four characteristics, which I'll describe briefly:

  • Atomic: This is the aforementioned all-or-nothing property. Even though a transaction comprises multiple operations, it is completed as a single logical unit of work. Either the whole thing succeeds or none of it does.
  • Consistent: We want our "transactional resource" (which in most cases means our database) to be consistent with reality. So for example if I have 4,132 widgets in stock after I sell you five of them, then I want the database to say that I have 4,132 widgets in stock after I run a sell(you, 5, widget) transaction. The consistency property means that after a transaction completes, the database (or whatever transactional resource we're using) matches up with the real world.
  • Isolated: In general we want to be able to run lots of transactions against the database at the same time, and we don't want to make a big mess out of things in the process. The isolation property means that when you run a transaction, it achieves its results without interference from other transactions. That doesn't mean that the transactions can't run concurrently—it just means that the transactions shouldn't corrupt each other in the process. In practice it's nontrivial to strike the right balance between concurrency and isolation; transactions however exhibit some level of isolation, and well-designed transactions exhibit the "right" amount of isolation.
  • Durable: This just means that after a transaction has ended, its results are made persistent. Probably they would have called this property "persistent" instead of "durable", but "ACIP" is not as cool as "ACID".

Defining Individual Transactions

Now that we know what transactions are, we need to understand how individual transactions are actually specified. Defining a transaction involves picking a chunk of code (maybe a method, maybe a set of methods, maybe a block of code inside a method) and setting values for the following five parameters:

  • Propagation behavior: When defining a transaction we must specify its "boundaries": where does the transaction start and where does it end? In Spring (and also in EJB), the boundaries of a transaction may or may not coincide with the boundaries of a Java method. In one respect this is not unlike using the synchronized keyword: if one synchronized method calls another on the same class, then the protected scope includes both methods, not just one, and so the boundaries do not coincide with a single method. But the difference is that with transactions you have a lot more flexibility as far as defining the boundaries. Certainly it is possible to enter a transaction starting from one method and then include additional method calls within the scope of that initial transaction. But you can do other things too, such as declare that calls to other methods open up new transactions, or that a given method must always run within the scope of an existing transaction, etc. I won't go over all the options here but there are seven and you can see them here: transaction propagation options. Probably PROPAGATION_REQUIRED is the most typical.
  • Isolation level: I mentioned above that in practice concurrency trades against isolation. (Once again there's an analogy with threads, incidentally.) You can specify the level of isolation you need for a given transaction; the general rule of thumb is assign the weakest isolation level you can safely get away with so as to maximize concurrency. Again I won't go into the details but you can find them here: transaction isolation levels. The most typical cases are ISOLATION_READ_COMMITTED and ISOLATION_REPEATABLE_READ. The ISOLATION_READ_UNCOMMITTED is so weak as to be almost useless in practice, and ISOLATION_SERIALIZABLE is so strong that you don't want to use it unless you really, really need the safety it provides: it's a concurrency-killer.
  • Timeout: I'm currently reading a great book on software development called Release It!: Design and Deploy Production-Ready Software, by Michael T. Nygard. In a nutshell this book makes the case that designing software against a functional requirements document isn't (at all) the same thing as designing software for the data center, and to do the latter you need to assume that serious bugs will infiltrate your production releases and design your software to deal with that reality. One of the key insights is that problems occur primarily at integration points, and one of the strategies for dealing with that is to use timeouts. Transaction timeouts allow the calling application to give up if the database hasn't completed the transaction within a specifiable interval of time.
  • Read-only: This flag indicates whether the transaction will be, well, read-only. If so, you can flag it as such and the underlying database or other resource can apply optimizations based on that fact.
  • Rollback behavior: By default, both Spring and EJB roll back a transaction (i.e., cancel it without applying any of the changes) when runtime exceptions, but not when checked exceptions occur. You can modify that behavior.

With that overview concluded, let's now examine Spring's annotation-based transaction management. It is ridiculously straightforward.

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

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 Annotations RefCard
Check out the new DZone Spring Annotations Refcard by Craig Walls!

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.