Managing transactions
161Declaring transactions
As defined in the txAdvice transaction advice, the transactional methods configured are divided into two categories: those whose names begin with add and everything else. The saveSpittle() method falls into the first category and is declared to require a transaction. The other methods are declared with propagation="supports"—
they’ll run in a transaction if one already exists, but they don’t need to run within a transaction.
When declaring a transaction using <tx:advice>, you’ll still need a transaction manager just like you did when using TransactionProxyFactoryBean. Choosing con-vention over configuration, <tx:advice> assumes that the transaction manager will be declared as a bean whose id is transactionManager. If you happen to give your transaction manager a different id (txManager, for instance), you’ll need to specify the id of the transaction manager in the transactionmanager attribute:
<tx:advice id="txAdvice"
transaction-manager="txManager">
...
</tx:advice>
On its own, <tx:advice> only defines an AOP advice for advising methods with trans-action boundaries. But this is only transtrans-action advice, not a complete transtrans-actional aspect. Nowhere in <tx:advice> did we indicate which beans should be advised—we need a pointcut for that. To completely define the transaction aspect, we must define an advisor. This is where the aop namespace gets involved. The following XML defines an advisor that uses the txAdvice advice to advise any beans that implement the SpitterService interface:
<aop:config>
<aop:advisor
pointcut="execution(* *..SpitterService.*(..))"
advice-ref="txAdvice"/>
</aop:config>
Table 6.4 The five facets of the transaction pentagon (see figure 6.3) are specified in the attributes of the <tx:method> element.
Attribute Purpose
isolation Specifies the transaction isolation level.
propagation Defines the transaction’s propagation rule.
read-only Specifies that a transaction be read-only.
Rollback rules:
rollback-for no-rollback-for
rollback-for specifies checked exceptions for which a transaction should be rolled back and not committed.
no-rollback-for specifies exceptions for which the transaction should continue and not be rolled back.
timeout Defines a timeout for a long-running transaction.
162 CHAPTER 6 Managing transactions
The pointcut attribute uses an AspectJ pointcut expression to indicate that this advi-sor should advise all methods of the SpitterService interface. The transaction advice, which is referenced with the advice-ref attribute to be the advice named txAdvice, defines which methods are actually run within a transaction as well as the transactional attributes for those methods.
Although the <tx:advice> element goes a long way toward making declarative transactions more palatable for Spring developers, Spring 2.0 has one more feature that makes it even nicer for those working in a Java 5 environment. Let’s look at how Spring transactions can be annotation driven.
6.4.3 Defining annotation-driven transactions
The <tx:advice> configuration element greatly simplifies the XML required for declarative transactions in Spring. What if I told you that it could be simplified even further? What if I told you that you only need to add a single line of XML to your Spring context in order to declare transactions?
In addition to the <tx:advice> element, the tx namespace provides the
<tx:annotation-driven> element. Using <tx:annotation-driven> is often as simple as the following line of XML:
<tx:annotation-driven />
That’s it! If you were expecting more, I apologize. I could make it slightly more inter-esting by specifying a specific transaction manager bean with the transactionmanager attribute (which defaults to transactionManager):
<tx:annotation-driven transaction-manager="txManager" />
Otherwise, there’s not much more to it. That single line of XML packs a powerful punch that lets you define transaction rules where they make the most sense: on the methods that are to be transactional.
Annotations are one of the biggest and most debated new features of Java 5. Anno-tations let you define metadata directly in your code rather than in external configu-ration files. I think they’re a perfect fit for declaring transactions.
The <tx:annotation-driven> configuration element tells Spring to examine all beans in the application context and to look for beans that are annotated with
@Transactional, either at the class level or at the method level. For every bean that is
@Transactional, <tx:annotation-driven> will automatically advise it with transac-tion advice. The transactransac-tion attributes of the advice will be defined by parameters of the @Transactional annotation.
For example, the following shows SpitterServiceImpl, updated to include the
@Transactional annotations.
163 Summary
@Transactional(propagation=Propagation.SUPPORTS, readOnly=true) public class SpitterServiceImpl implements SpitterService { ...
@Transactional(propagation=Propagation.REQUIRED, readOnly=false) public void addSpitter(Spitter spitter) {
...
} ...
}
At the class level, SpitterServiceImpl has been annotated with an @Transactional annotation that says that all methods will support transaction and be read-only. At the method level, the saveSpittle() method has been annotated to indicate that this method requires a transactional context.
6.5 Summary
Transactions are an important part of enterprise application development that leads to more robust software. They ensure an all-or-nothing behavior, preventing data from being inconsistent should the unexpected occur. They also support concurrency by preventing concurrent application threads from getting in each other’s way as they work with the same data.
Spring supports both programmatic and declarative transaction management. In either case, Spring shields you from having to work directly with a specific transaction management implementation by abstracting the transaction management platform behind a common API.
Spring employs its own AOP framework to support declarative transaction manage-ment. Spring’s declarative transaction support rivals that of EJB’s CMT, enabling you to declare more than just propagation behavior on POJOs, including isolation levels, read-only optimizations, and rollback rules for specific exceptions.
This chapter showed you how to bring declarative transactions into the Java 5 pro-gramming model using annotations. With the introduction of Java 5 annotations, making a method transactional is simply a matter of tagging it with the appropriate transaction annotation.
As you’ve seen, Spring extends the power of declarative transactions to POJOs. This is an exciting development—declarative transactions were previously only available to EJBs. But declarative transactions are only the beginning of what Spring has to offer to POJOs. In the next chapter, you’ll see how Spring extends declarative security to POJOs.
Listing 6.3 Annotating the spitter service to be transactional
164