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.
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.