2009-04-15 05:37:40 +08:00
<?xml version="1.0" encoding="UTF-8"?>
2009-04-30 12:16:07 +08:00
< !DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
2009-04-15 05:37:40 +08:00
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
2009-03-19 04:00:49 +08:00
<chapter id= "transaction" >
<title > Transaction management</title>
<section id= "transaction-intro" >
<title > Introduction</title>
<para > One of the most compelling reasons to use the Spring Framework is the
comprehensive transaction support. The Spring Framework provides a consistent
abstraction for transaction management that delivers the following benefits:</para>
<itemizedlist >
<listitem >
<para > Provides a consistent programming model across different
transaction APIs such as JTA, JDBC, Hibernate, JPA, and JDO.</para>
</listitem>
<listitem >
<para > Supports <link linkend= "transaction-declarative" > declarative transaction management</link> .</para>
</listitem>
<listitem >
<para > Provides a simpler API for <link linkend= "transaction-programmatic" > programmatic</link>
transaction management than a number of complex transaction APIs such as JTA.</para>
</listitem>
<listitem >
<para > Integrates very well with Spring's various data access abstractions.</para>
</listitem>
</itemizedlist>
<para > This chapter is divided up into a number of sections, each detailing one of the
value-adds or technologies of the Spring Framework's transaction support. The chapter
closes up with some discussion of best practices surrounding transaction management
(for example, choosing between declarative and programmatic transaction management).</para>
<itemizedlist >
<listitem >
<para > The first section, entitled
<link linkend= "transaction-motivation" > Motivations</link> ,
describes <emphasis > why</emphasis> one would want to use
the Spring Framework's transaction abstraction as opposed to EJB CMT
or driving transactions via a proprietary API such
as Hibernate.</para>
</listitem>
<listitem >
<para > The second section, entitled
<link linkend= "transaction-strategies" > Key abstractions</link>
outlines the core classes in the Spring Framework's transaction support,
as well as how to configure and obtain <interfacename > DataSource</interfacename>
instances from a variety of sources.</para>
</listitem>
<listitem >
<para > The third section, entitled
<link linkend= "transaction-declarative" > Declarative transaction management</link> ,
covers the Spring Framework's support for declarative transaction management.</para>
</listitem>
<listitem >
<para > The fourth section, entitled
<link linkend= "transaction-programmatic" > Programmatic transaction management</link> ,
covers the Spring Framework's support for programmatic (that is, explicitly
coded) transaction management.</para>
</listitem>
</itemizedlist>
</section>
<section id= "transaction-motivation" >
<title > Motivations</title>
<sidebar >
<title > Is an application server needed for transaction management?</title>
<para > The Spring Framework's transaction management support significantly changes
traditional thinking as to when a J2EE application requires an application
server.</para>
<para > In particular, you don't need an application server just to have
declarative transactions via EJB. In fact, even if you have an application
server with powerful JTA capabilities, you may well decide that the Spring Framework's
declarative transactions offer more power and a much more productive
programming model than EJB CMT.</para>
<para > Typically you need an application server's JTA capability only if you need to
enlist multiple transactional resources, and for many applications being able
to handle transactions across multiple resources isn't a requirement.
For example, many high-end applications use a single, highly scalable
database (such as Oracle 9i RAC). Standalone transaction managers such as
<ulink url= "http://www.atomikos.com/" > Atomikos Transactions</ulink> and
<ulink url= "http://jotm.objectweb.org/" > JOTM</ulink> are other options. (Of course
you may need other application server capabilities such as JMS and JCA.)</para>
<para > The most important point is that with the Spring Framework <emphasis > you can
choose when to scale your application up to a full-blown application
server</emphasis> . Gone are the days when the only alternative to using
EJB CMT or JTA was to write code using local transactions such as those
on JDBC connections, and face a hefty rework if you ever needed that code
to run within global, container-managed transactions. With the Spring Framework,
only configuration needs to change so that your code doesn't have to.</para>
</sidebar>
<para > Traditionally, J2EE developers have had two choices for transaction
management: <emphasis > global</emphasis> or <emphasis > local</emphasis> transactions.
Global transactions are managed by the application server, using the Java Transaction
API (JTA). Local transactions are resource-specific: the most common example would
be a transaction associated with a JDBC connection. This choice has profound
implications. For instance, global transactions provide the ability to work with multiple
transactional resources (typically relational databases and message queues).
With local transactions, the application server is not involved in
transaction management and cannot help ensure correctness across multiple
resources. (It is worth noting that most applications use a single transaction
resource.)</para>
<formalpara >
<title > Global Transactions</title>
<para > Global transactions have a significant downside, in that code needs
to use JTA, and JTA is a cumbersome API to use (partly due to its exception
model). Furthermore, a JTA <interfacename > UserTransaction</interfacename>
normally needs to be sourced from JNDI: meaning that we need to use
<emphasis > both</emphasis> JNDI <emphasis > and</emphasis> JTA to use JTA.
Obviously all use of global transactions limits the reusability of application
code, as JTA is normally only available in an application server environment. </para>
<para > Previously, the preferred way to use global transactions was via EJB
<emphasis > CMT</emphasis> (<emphasis > Container Managed Transaction</emphasis> ):
CMT is a form of <emphasis role= "bold" > declarative transaction management</emphasis>
(as distinguished from <emphasis role= "bold" > programmatic transaction management</emphasis> ).
EJB CMT removes the need for transaction-related JNDI lookups - although of course
the use of EJB itself necessitates the use of JNDI. It removes most of the need (although
not entirely) to write Java code to control transactions. The significant
downside is that CMT is tied to JTA and an application server
environment. Also, it is only available if one chooses to implement
business logic in EJBs, or at least behind a transactional EJB facade. The
negatives around EJB in general are so great that this is not an
attractive proposition, especially in the face of compelling alternatives for
declarative transaction management.</para>
</formalpara>
<formalpara >
<title > Local Transactions</title>
<para > Local transactions may be easier to use, but have significant
disadvantages: they cannot work across multiple transactional resources.
For example, code that manages transactions using a JDBC connection cannot
run within a global JTA transaction. Another downside is that local
transactions tend to be invasive to the programming model.</para>
</formalpara>
<para > Spring resolves these problems. It enables application developers to
use a <emphasis > consistent</emphasis> programming model <emphasis > in any
environment</emphasis> . You write your code once, and it can benefit from
different transaction management strategies in different environments.
The Spring Framework provides both declarative and programmatic transaction management.
Declarative transaction management is preferred by most users, and is
recommended in most cases.</para>
<para > With programmatic transaction management, developers work with the
Spring Framework transaction abstraction, which can run over any underlying
transaction infrastructure. With the preferred declarative model,
developers typically write little or no code related to transaction
management, and hence don't depend on the Spring Framework's transaction API
(or indeed on any other transaction API).</para>
</section>
<section id= "transaction-strategies" >
<title > Key abstractions</title>
<para > The key to the Spring transaction abstraction is the notion of a
<emphasis > transaction strategy</emphasis> . A transaction strategy is
defined by the
<interfacename > org.springframework.transaction.PlatformTransactionManager</interfacename>
interface, shown below:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[public interface PlatformTransactionManager {
2009-03-19 04:00:49 +08:00
TransactionStatus getTransaction(TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}]]></programlisting>
<para > This is primarily an SPI interface, although it can be used
<link linkend= "transaction-programmatic-ptm" > programmatically</link> .
Note that in keeping with the Spring Framework's philosophy,
<interfacename > PlatformTransactionManager</interfacename> is
an <emphasis > interface</emphasis> , and can thus be easily mocked or stubbed
as necessary. Nor is it tied to a lookup strategy such as JNDI:
<interfacename > PlatformTransactionManager</interfacename> implementations
are defined like any other object (or bean) in the Spring Framework's IoC container.
This benefit alone makes it a worthwhile abstraction even when working
with JTA: transactional code can be tested much more easily than if it
used JTA directly.</para>
<para > Again in keeping with Spring's philosophy, the <exceptionname > TransactionException</exceptionname>
that can be thrown by any of the <interfacename > PlatformTransactionManager</interfacename>
interface's methods is <emphasis > unchecked</emphasis> (that is it extends the
<exceptionname > java.lang.RuntimeException</exceptionname> class). Transaction infrastructure
failures are almost invariably fatal. In rare cases where application code can actually
recover from a transaction failure, the application developer can still choose to catch
and handle <exceptionname > TransactionException</exceptionname> . The salient point is
that developers are not <emphasis > forced</emphasis> to do so.</para>
<para > The <methodname > getTransaction(..)</methodname> method returns a
<interfacename > TransactionStatus</interfacename> object, depending on a
<interfacename > TransactionDefinition</interfacename> parameter. The returned
<interfacename > TransactionStatus</interfacename> might represent a new or
existing transaction (if there were a matching transaction in the current
call stack - with the implication being that (as with J2EE transaction contexts)
a <interfacename > TransactionStatus</interfacename> is associated with a
<emphasis role= "bold" > thread</emphasis> of execution).</para>
<para > The <interfacename > TransactionDefinition</interfacename> interface specifies:</para>
<itemizedlist >
<listitem >
<para > <emphasis role= "bold" > Isolation</emphasis> : the
degree of isolation this transaction has from the work of other
transactions. For example, can this transaction see uncommitted
writes from other transactions?</para>
</listitem>
<listitem >
<para > <emphasis role= "bold" > Propagation</emphasis> :
normally all code executed within a transaction scope will run in that
transaction. However, there are several options specifying behavior if
a transactional method is executed when a transaction context already
exists: for example, simply continue running in the existing transaction
(the common case); or suspending the existing transaction and creating
a new transaction. <emphasis > Spring offers all of the transaction propagation
options familiar from EJB CMT</emphasis> . (Some details regarding the semantics of transaction
propagation in Spring can be found in the section entitled <xref linkend= "tx-propagation" /> .</para>
</listitem>
<listitem >
<para > <emphasis role= "bold" > Timeout</emphasis> : how long
this transaction may run before timing out (and automatically being
rolled back by the underlying transaction infrastructure).</para>
</listitem>
<listitem >
<para > <emphasis role= "bold" > Read-only status</emphasis> : a read-only
transaction does not modify any data. Read-only transactions can be a
useful optimization in some cases (such as when using Hibernate).</para>
</listitem>
</itemizedlist>
<para > These settings reflect standard transactional concepts. If necessary,
please refer to a resource discussing transaction isolation levels and other
core transaction concepts because understanding such core concepts is essential
to using the Spring Framework or indeed any other transaction management solution.</para>
<para > The <interfacename > TransactionStatus</interfacename> interface provides a simple
way for transactional code to control transaction execution and query
transaction status. The concepts should be familiar, as they are common to
all transaction APIs:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[public interface TransactionStatus {
2009-03-19 04:00:49 +08:00
boolean isNewTransaction();
void setRollbackOnly();
boolean isRollbackOnly();
}]]></programlisting>
<para > Regardless of whether you opt for declarative or programmatic transaction
management in Spring, defining the correct
<interfacename > PlatformTransactionManager</interfacename> implementation is
absolutely essential. In good Spring fashion, this important definition typically
is made using via Dependency Injection.</para>
<para > <interfacename > PlatformTransactionManager</interfacename> implementations
normally require knowledge of the environment in which they work: JDBC, JTA,
Hibernate, etc The following examples from the
<literal > dataAccessContext-local.xml</literal> file from Spring's
<emphasis role= "bold" > jPetStore</emphasis> sample application show how a local
<interfacename > PlatformTransactionManager</interfacename> implementation can be
defined. (This will work with plain JDBC.)</para>
<para > We must define a JDBC <interfacename > DataSource</interfacename> , and
then use the Spring <classname > DataSourceTransactionManager</classname> , giving
it a reference to the <interfacename > DataSource</interfacename> .</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
2009-03-19 04:00:49 +08:00
<property name= "driverClassName" value= "${jdbc.driverClassName}" />
<property name= "url" value= "${jdbc.url}" />
<property name= "username" value= "${jdbc.username}" />
<property name= "password" value= "${jdbc.password}" />
</bean> ]]></programlisting>
<para > The related <interfacename > PlatformTransactionManager</interfacename> bean
definition will look like this:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
2009-03-19 04:00:49 +08:00
<property name= "dataSource" ref= "dataSource" />
</bean> ]]></programlisting>
<para > If we use JTA in a J2EE container, as in the <filename > 'dataAccessContext-jta.xml'</filename>
file from the same sample application, we use a container <interfacename > DataSource</interfacename> ,
obtained via JNDI, in conjunction with Spring's <classname > JtaTransactionManager</classname> .
The <classname > JtaTransactionManager</classname> doesn't need to know about the
<interfacename > DataSource</interfacename> , or any other specific resources, as
it will use the container's global transaction management infrastructure.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2009-03-19 04:00:49 +08:00
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd">
<jee:jndi-lookup id= "dataSource" jndi-name= "jdbc/jpetstore" />
<bean id= "txManager" class= "org.springframework.transaction.jta.JtaTransactionManager" />
]]><lineannotation > < !-- other <literal > < bean/> </literal> definitions here --> </lineannotation> < ![CDATA[
</beans> ]]></programlisting>
<note >
<para > The above definition of the <literal > 'dataSource'</literal> bean uses the
<literal > < jndi-lookup/> </literal> tag from the <literal > 'jee'</literal>
namespace. For more information on schema-based configuration, see <xref linkend= "xsd-config" /> ,
and for more information on the <literal > < jee/> </literal> tags
see the section entitled <xref linkend= "xsd-config-body-schemas-jee" /> .</para>
</note>
<para > We can also use Hibernate local transactions easily, as shown in the
following examples from the Spring Framework's <emphasis role= "bold" > PetClinic</emphasis>
sample application. In this case, we need to define a Hibernate
<classname > LocalSessionFactoryBean</classname> , which application code will
use to obtain Hibernate <interfacename > Session</interfacename> instances.</para>
<para > The <interfacename > DataSource</interfacename> bean definition will be
similar to the one shown previously (and thus is not shown). If the
<interfacename > DataSource</interfacename> is managed by the JEE container it should
be non-transactional as the Spring Framework, rather than the JEE container, will
manage transactions.</para>
<para > The <literal > 'txManager'</literal> bean in this case is of the
<classname > HibernateTransactionManager</classname> type. In the same way as the
<classname > DataSourceTransactionManager</classname> needs a reference to the
<interfacename > DataSource</interfacename> , the
<classname > HibernateTransactionManager</classname> needs a reference to the
<interfacename > SessionFactory</interfacename> .</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
2009-03-19 04:00:49 +08:00
<property name= "dataSource" ref= "dataSource" />
<property name= "mappingResources" >
<list >
<value > org/springframework/samples/petclinic/hibernate/petclinic.hbm.xml</value>
</list>
</property>
<property name= "hibernateProperties" >
<value >
hibernate.dialect=${hibernate.dialect}
</value>
</property>
</bean>
<bean id= "txManager" class= "org.springframework.orm.hibernate3.HibernateTransactionManager" >
<property name= "sessionFactory" ref= "sessionFactory" />
</bean> ]]></programlisting>
<para > With Hibernate and JTA transactions, we can simply use the
<classname > JtaTransactionManager</classname> as with JDBC or any other resource strategy.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>]]> </programlisting>
2009-03-19 04:00:49 +08:00
<para > Note that this is identical to JTA configuration for any resource,
as these are global transactions, which can enlist any transactional
resource.</para>
<remark >
<para > In all these cases, application code will not need to change at
all. We can change how transactions are managed merely by changing
configuration, even if that change means moving from local to global
transactions or vice versa.</para>
</remark>
</section>
<section id= "tx-resource-synchronization" >
<title > Resource synchronization with transactions</title>
<para > It should now be clear how different transaction managers are
created, and how they are linked to related resources which need to be
synchronized to transactions (for example <classname > DataSourceTransactionManager</classname>
to a JDBC <interfacename > DataSource</interfacename> ,
<classname > HibernateTransactionManager</classname> to a Hibernate
<interfacename > SessionFactory</interfacename> , and so forth). There remains the question
however of how the application code, directly or indirectly using a
persistence API (such as JDBC, Hibernate, and JDO), ensures that these resources
are obtained and handled properly in terms of proper
creation/reuse/cleanup and trigger (optionally) transaction
synchronization via the relevant <interfacename > PlatformTransactionManager</interfacename> .</para>
<section id= "tx-resource-synchronization-high" >
<title > High-level approach</title>
<para > The preferred approach is to use Spring's highest level
persistence integration APIs. These do not replace the native APIs, but
internally handle resource creation/reuse, cleanup, optional
transaction synchronization of the resources and exception mapping so
that user data access code doesn't have to worry about these concerns at
all, but can concentrate purely on non-boilerplate persistence logic.
Generally, the same <emphasis > template</emphasis> approach is used
for all persistence APIs, with examples including the
<classname > JdbcTemplate</classname> , <classname > HibernateTemplate</classname> ,
and <classname > JdoTemplate</classname> classes (detailed in subsequent chapters
of this reference documentation.</para>
</section>
<section id= "tx-resource-synchronization-low" >
<title > Low-level approach</title>
<para > At a lower level exist classes such as
<classname > DataSourceUtils</classname> (for JDBC),
<classname > SessionFactoryUtils</classname> (for Hibernate),
<classname > PersistenceManagerFactoryUtils</classname> (for JDO), and so on.
When it is preferable for application code to deal directly with the
resource types of the native persistence APIs, these classes ensure that
proper Spring Framework-managed instances are obtained, transactions are
(optionally) synchronized, and exceptions which happen in the process
are properly mapped to a consistent API.</para>
<para > For example, in the case of JDBC, instead of the traditional JDBC approach of
calling the <literal > getConnection()</literal> method on the
<interfacename > DataSource</interfacename> , you would instead use Spring's
<classname > org.springframework.jdbc.datasource.DataSourceUtils</classname>
class as follows:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > <![CDATA[Connection conn = DataSourceUtils.getConnection(dataSource);]]> </programlisting>
2009-03-19 04:00:49 +08:00
<para > If an existing transaction exists, and already has a connection
synchronized (linked) to it, that instance will be returned. Otherwise,
the method call will trigger the creation of a new connection, which
will be (optionally) synchronized to any existing transaction, and
made available for subsequent reuse in that same transaction. As mentioned,
this has the added advantage that any <exceptionname > SQLException</exceptionname>
will be wrapped in a Spring Framework
<exceptionname > CannotGetJdbcConnectionException</exceptionname> - one of the Spring
Framework's hierarchy of unchecked DataAccessExceptions. This gives you more
information than can easily be obtained from the
<exceptionname > SQLException</exceptionname> , and ensures portability across
databases: even across different persistence technologies.</para>
<para > It should be noted that this will also work fine without Spring
transaction management (transaction synchronization is optional), so you
can use it whether or not you are using Spring for transaction
management.</para>
<para > Of course, once you've used Spring's JDBC support or Hibernate
support, you will generally prefer not to use
<classname > DataSourceUtils</classname> or the other helper classes, because
you'll be much happier working via the Spring abstraction than directly
with the relevant APIs. For example, if you use the Spring
<classname > JdbcTemplate</classname> or <literal > jdbc.object</literal>
package to simplify your use of JDBC, correct connection retrieval happens
behind the scenes and you won't need to write any special code.</para>
</section>
<section id= "tx-resource-synchronization-tadsp" >
<title > <classname > TransactionAwareDataSourceProxy</classname> </title>
<para > At the very lowest level exists the
<classname > TransactionAwareDataSourceProxy</classname> class. This is a
proxy for a target <interfacename > DataSource</interfacename> , which wraps the
target <interfacename > DataSource</interfacename> to add awareness of Spring-managed
transactions. In this respect, it is similar to a transactional JNDI
<interfacename > DataSource</interfacename> as provided by a J2EE server.</para>
<para > It should almost never be necessary or desirable to use this
class, except when existing code exists which must be called and passed
a standard JDBC <interfacename > DataSource</interfacename> interface implementation.
In that case, it's possible to still have this code be usable, but
participating in Spring managed transactions. It is preferable to write
your new code using the higher level abstractions mentioned
above.</para>
</section>
</section>
<section id= "transaction-declarative" >
<title > Declarative transaction management</title>
<remark > Most users of the Spring Framework choose declarative transaction management.
It is the option with the least impact on application code, and hence is most
consistent with the ideals of a <emphasis > non-invasive</emphasis>
lightweight container.</remark>
<para > The Spring Framework's declarative transaction management is made possible
with Spring AOP, although, as the transactional aspects code comes with the
Spring Framework distribution and may be used in a boilerplate fashion, AOP concepts
do not generally have to be understood to make effective use of this code.</para>
<para > It may be helpful to begin by considering EJB CMT and explaining the
similarities and differences with the Spring Framework's declarative transaction
management. The basic approach is similar: it is possible to specify
transaction behavior (or lack of it) down to individual method level. It is
possible to make a <methodname > setRollbackOnly()</methodname> call within a
transaction context if necessary. The differences are:</para>
<itemizedlist >
<listitem >
<para > Unlike EJB CMT, which is tied to JTA, the Spring Framework's
declarative transaction management works in any environment. It can
work with JDBC, JDO, Hibernate or other transactions under the covers,
with configuration changes only.</para>
</listitem>
<listitem >
<para > The Spring Framework enables declarative transaction management
to be applied to any class, not merely special classes such as EJBs.</para>
</listitem>
<listitem >
<para > The Spring Framework offers declarative
<link linkend= "transaction-declarative-rolling-back" > <emphasis > rollback rules</emphasis> :</link> this is
a feature with no EJB equivalent. Both programmatic and declarative support for rollback rules is
provided.</para>
</listitem>
<listitem >
<para > The Spring Framework gives you an opportunity to customize transactional
behavior, using AOP. For example, if you want to insert custom
behavior in the case of transaction rollback, you can. You can also
add arbitrary advice, along with the transactional advice. With EJB
CMT, you have no way to influence the container's transaction
management other than <methodname > setRollbackOnly()</methodname> .</para>
</listitem>
<listitem >
<para > The Spring Framework does not support propagation of transaction contexts across remote calls, as
do high-end application servers. If you need this feature, we recommend that you use EJB. However,
consider carefully before using such a feature, because normally, one does not want transactions to
span remote calls.</para>
</listitem>
</itemizedlist>
<sidebar >
<title > Where is <classname > TransactionProxyFactoryBean</classname> ?</title>
<para > Declarative transaction configuration in versions of Spring 2.0 and above
differs considerably from previous versions of Spring. The main difference is
that there is no longer any need to configure
<classname > TransactionProxyFactoryBean</classname> beans.</para>
<para > The old, pre-Spring 2.0 configuration style is still 100%
valid configuration; think of the new <literal > < tx:tags/> </literal>
as simply defining <classname > TransactionProxyFactoryBean</classname> beans
on your behalf.</para>
</sidebar>
<para > The concept of rollback rules is important: they enable us to
specify which exceptions (and throwables) should cause automatic roll
back. We specify this declaratively, in configuration, not in Java code.
So, while we can still call <methodname > setRollbackOnly()</methodname> on the
<interfacename > TransactionStatus</interfacename> object to roll the current
transaction back programmatically, most often we can specify a rule that
<exceptionname > MyApplicationException</exceptionname> must always result in
rollback. This has the significant advantage that business objects don't need
to depend on the transaction infrastructure. For example, they typically
don't need to import any Spring APIs, transaction or other.</para>
<para > While the EJB default behavior is for the EJB container to
automatically roll back the transaction on a <emphasis > system
exception</emphasis> (usually a runtime exception), EJB CMT does not roll
back the transaction automatically on an <emphasis > application exception</emphasis>
(that is, a checked exception other than <exceptionname > java.rmi.RemoteException</exceptionname> ).
While the Spring default behavior for declarative transaction management follows
EJB convention (roll back is automatic only on unchecked exceptions), it is often
useful to customize this.</para>
<section id= "tx-decl-explained" >
<title > Understanding the Spring Framework's declarative transaction implementation</title>
<para > The aim of this section is to dispel the mystique that is sometimes associated
with the use of declarative transactions. It is all very well for this reference
documentation simply to tell you to annotate your classes with the
<interfacename > @Transactional</interfacename> annotation, add the line
(<literal > '< tx:annotation-driven/> '</literal> ) to your configuration,
and then expect you to understand how it all works. This section will explain the
inner workings of the Spring Framework's declarative transaction infrastructure to
help you navigate your way back upstream to calmer waters in the event of
transaction-related issues.</para>
<para > The most important concepts to grasp with regard to the Spring Framework's
declarative transaction support are that this support is enabled
<link linkend= "aop-understanding-aop-proxies" > <emphasis > via AOP proxies</emphasis> </link> ,
and that the transactional advice is driven by <emphasis > metadata</emphasis> (currently
XML- or annotation-based). The combination of AOP with transactional metadata yields
an AOP proxy that uses a <classname > TransactionInterceptor</classname> in conjunction
with an appropriate <classname > PlatformTransactionManager</classname> implementation
to drive transactions <emphasis > around method invocations</emphasis> .</para>
<note >
<para > Although knowledge of Spring AOP is not required to use Spring's declarative
transaction support, it can help. Spring AOP is thoroughly covered in the chapter
entitled <xref linkend= "aop" /> .</para>
</note>
<para > Conceptually, calling a method on a transactional proxy looks like this...</para>
<para >
<mediaobject >
<imageobject role= "fo" >
<imagedata fileref= "images/tx.png" format= "PNG" align= "center" />
</imageobject>
<imageobject role= "html" >
<imagedata fileref= "images/tx.png" format= "PNG" align= "center" />
</imageobject>
</mediaobject>
</para>
</section>
<section id= "transaction-declarative-first-example" >
<title > A first example</title>
<para > Consider the following interface, and its attendant implementation.
(The intent is to convey the concepts, and using the rote <classname > Foo</classname> and
<classname > Bar</classname> tropes means that you can concentrate on the transaction
usage and not have to worry about the domain model.)</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > <lineannotation > // the service interface that we want to make transactional</lineannotation> < ![CDATA[
2009-03-19 04:00:49 +08:00
package x.y.service;
public interface FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}]]></programlisting>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > <lineannotation > // an implementation of the above interface</lineannotation> < ![CDATA[
2009-03-19 04:00:49 +08:00
package x.y.service;
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
throw new UnsupportedOperationException();
}
public Foo getFoo(String fooName, String barName) {
throw new UnsupportedOperationException();
}
public void insertFoo(Foo foo) {
throw new UnsupportedOperationException();
}
public void updateFoo(Foo foo) {
throw new UnsupportedOperationException();
}
}]]></programlisting>
<para > <emphasis > (For the purposes of this example, the fact that the
<classname > DefaultFooService</classname> class throws
<exceptionname > UnsupportedOperationException</exceptionname> instances in the body
of each implemented method is good; it will allow us to see transactions being created
and then rolled back in response to the <exceptionname > UnsupportedOperationException</exceptionname>
instance being thrown.)</emphasis> </para>
<para > Let's assume that the first two methods of the <interfacename > FooService</interfacename>
interface (<literal > getFoo(String)</literal> and <literal > getFoo(String, String)</literal> )
have to execute in the context of a transaction with read-only semantics, and that
the other methods (<literal > insertFoo(Foo)</literal> and
<literal > updateFoo(Foo)</literal> ) have to execute in the context of a transaction
with read-write semantics. Don't worry about taking the following configuration in
all at once; everything will be explained in detail in the next few paragraphs.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <lineannotation > < !-- from the file <literal > 'context.xml'</literal> --> </lineannotation> < ![CDATA[
2009-03-19 04:00:49 +08:00
<?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:aop="http://www.springframework.org/schema/aop"
]]><lineannotation > <emphasis role= "bold" > xmlns:tx="http://www.springframework.org/schema/tx"</emphasis> </lineannotation> < ![CDATA[
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
]]><lineannotation > <emphasis role= "bold" > http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd</emphasis> </lineannotation> < ![CDATA[
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
]]><lineannotation > < !-- this is the service object that we want to make transactional --> </lineannotation> < ![CDATA[
<bean id= "fooService" class= "x.y.service.DefaultFooService" />
]]><lineannotation > < !-- the transactional advice (what 'happens'; see the <literal > < aop:advisor/> </literal> bean below) --> </lineannotation> < ![CDATA[
<tx:advice id= "txAdvice" transaction-manager= "txManager" >
]]><lineannotation > < !-- the transactional semantics... --> </lineannotation> < ![CDATA[
<tx:attributes >
]]><lineannotation > < !-- all methods starting with <literal > 'get'</literal> are read-only --> </lineannotation> < ![CDATA[
<tx:method name= "get*" read-only= "true" />
]]><lineannotation > < !-- other methods use the default transaction settings (see below) --> </lineannotation> < ![CDATA[
<tx:method name= "*" />
</tx:attributes>
</tx:advice>
]]><lineannotation > < !-- ensure that the above transactional advice runs for any execution
of an operation defined by the <interfacename > FooService</interfacename> interface --> </lineannotation> < ![CDATA[
<aop:config >
<aop:pointcut id= "fooServiceOperation" expression= "execution(* x.y.service.FooService.*(..))" />
<aop:advisor advice-ref= "txAdvice" pointcut-ref= "fooServiceOperation" />
</aop:config>
]]><lineannotation > < !-- don't forget the <interfacename > DataSource</interfacename> --> </lineannotation> < ![CDATA[
<bean id= "dataSource" class= "org.apache.commons.dbcp.BasicDataSource" destroy-method= "close" >
<property name= "driverClassName" value= "oracle.jdbc.driver.OracleDriver" />
<property name= "url" value= "jdbc:oracle:thin:@rj-t42:1521:elvis" />
<property name= "username" value= "scott" />
<property name= "password" value= "tiger" />
</bean>
]]><lineannotation > < !-- similarly, don't forget the <interfacename > PlatformTransactionManager</interfacename> --> </lineannotation> < ![CDATA[
<bean id= "txManager" class= "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name= "dataSource" ref= "dataSource" />
</bean>
]]><lineannotation > < !-- other <literal > < bean/> </literal> definitions here --> </lineannotation> < ![CDATA[
</beans> ]]></programlisting>
<para > Let's pick apart the above configuration. We have a service object
(the <literal > 'fooService'</literal> bean) that we want to make transactional.
The transaction semantics that we want to apply are encapsulated in the
<literal > < tx:advice/> </literal> definition. The
<literal > < tx:advice/> </literal> definition reads as
<quote > <emphasis > ... all methods on starting with <literal > 'get'</literal> are to execute
in the context of a read-only transaction, and all other methods are to execute
with the default transaction semantics</emphasis> </quote> . The
<literal > 'transaction-manager'</literal> attribute of the
<literal > < tx:advice/> </literal> tag is set to the
name of the <interfacename > PlatformTransactionManager</interfacename> bean
that is going to actually <emphasis > drive</emphasis> the transactions (in this
case the <literal > 'txManager'</literal> bean).</para>
<tip >
<para > You can actually omit the <literal > 'transaction-manager'</literal>
attribute in the transactional advice (<literal > < tx:advice/> </literal> )
if the bean name of the <interfacename > PlatformTransactionManager</interfacename>
that you want to wire in has the name <literal > 'transactionManager'</literal> .
If the <interfacename > PlatformTransactionManager</interfacename> bean
that you want to wire in has any other name, then you have to be explicit
and use the <literal > 'transaction-manager'</literal> attribute as in the example above.</para>
</tip>
<para > The <literal > < aop:config/> </literal> definition ensures that the transactional
advice defined by the <literal > 'txAdvice'</literal> bean actually executes at the appropriate
points in the program. First we define a pointcut that matches the execution of any
operation defined in the <interfacename > FooService</interfacename> interface
(<literal > 'fooServiceOperation'</literal> ). Then we associate the pointcut with the
<literal > 'txAdvice'</literal> using an advisor. The result indicates that at the execution
of a <literal > 'fooServiceOperation'</literal> , the advice defined by <literal > 'txAdvice'</literal>
will be run.</para>
<para > The expression defined within the <literal > < aop:pointcut/> </literal>
element is an AspectJ pointcut expression; see the chapter entitled <xref linkend= "aop" />
for more details on pointcut expressions in Spring 2.0.</para>
<para > A common requirement is to make an entire service layer transactional.
The best way to do this is simply to change the pointcut expression to match
any operation in your service layer. For example:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<aop:config>
2009-03-19 04:00:49 +08:00
<aop:pointcut id= "fooServiceMethods" expression= "execution(* x.y.service.*.*(..))" />
<aop:advisor advice-ref= "txAdvice" pointcut-ref= "fooServiceMethods" />
</aop:config> ]]></programlisting>
<para > <emphasis > (This example assumes that all your service interfaces are defined
in the <literal > 'x.y.service'</literal> package; see the chapter entitled
<xref linkend= "aop" /> for more details.)</emphasis> </para>
<para > Now that we've analyzed the configuration, you may be asking
yourself, <quote > <emphasis > Okay... but what does all this configuration actually
do?</emphasis> </quote> .</para>
<para > The above configuration is going to effect the creation of a
transactional proxy around the object that is created from the
<literal > 'fooService'</literal> bean definition. The proxy will be configured
with the transactional advice, so that when an appropriate method is invoked
<emphasis > on the proxy</emphasis> , a transaction <emphasis > may</emphasis>
be started, suspended, be marked as read-only, etc., depending on the
transaction configuration associated with that method. Consider the following
program that test drives the above configuration.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[public final class Boot {
2009-03-19 04:00:49 +08:00
public static void main(final String[] args) throws Exception {
ApplicationContext ctx = new ClassPathXmlApplicationContext("context.xml", Boot.class);
FooService fooService = (FooService) ctx.getBean("fooService");
fooService.insertFoo (new Foo());
}
}]]></programlisting>
<para > The output from running the above program will look something
like this. <emphasis > (Please note that the Log4J output and the stacktrace
from the <exceptionname > UnsupportedOperationException</exceptionname> thrown by the
<methodname > insertFoo(..)</methodname> method of the
<classname > DefaultFooService</classname> class have been truncated in
the interest of clarity.)</emphasis> </para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <lineannotation > <emphasis role= "bold" > < !-- the Spring container is starting up... --> </emphasis> </lineannotation> < ![CDATA[
2009-03-19 04:00:49 +08:00
[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy
for bean 'fooService' with 0 common interceptors and 1 specific interceptors
]]><lineannotation > <emphasis role= "bold" > < !-- the <classname > DefaultFooService</classname> is actually proxied --> </emphasis> </lineannotation> < ![CDATA[
[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]
]]><lineannotation > <emphasis role= "bold" > < !-- ... the <literal > insertFoo(..)</literal> method is now being invoked on the proxy --> </emphasis> </lineannotation> < ![CDATA[
[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo
]]><lineannotation > <emphasis role= "bold" > < !-- the transactional advice kicks in here... --> </emphasis> </lineannotation> < ![CDATA[
[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]
[DataSourceTransactionManager] - Acquired Connection
[org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction
]]><lineannotation > <emphasis role= "bold" > < !-- the <literal > insertFoo(..)</literal> method from <classname > DefaultFooService</classname> throws an exception... --> </emphasis> </lineannotation> < ![CDATA[
[RuleBasedTransactionAttribute] - Applying rules to determine whether transaction should
rollback on java.lang.UnsupportedOperationException
[TransactionInterceptor] - Invoking rollback for transaction on x.y.service.FooService.insertFoo
due to throwable [java.lang.UnsupportedOperationException]
]]><lineannotation > <emphasis role= "bold" > < !-- and the transaction is rolled back (by default, <exceptionname > RuntimeException</exceptionname> instances cause rollback) --> </emphasis> </lineannotation> < ![CDATA[
[DataSourceTransactionManager] - Rolling back JDBC transaction on Connection
[org.apache.commons.dbcp.PoolableConnection@a53de4]
[DataSourceTransactionManager] - Releasing JDBC Connection after transaction
[DataSourceUtils] - Returning JDBC Connection to DataSource
Exception in thread "main" java.lang.UnsupportedOperationException
at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)
]]><lineannotation > <emphasis role= "bold" > < !-- AOP infrastructure stack trace elements removed for clarity --> </emphasis> </lineannotation> < ![CDATA[
at $Proxy0.insertFoo(Unknown Source)
at Boot.main(Boot.java:11)]]></programlisting>
</section>
<section id= "transaction-declarative-rolling-back" >
<title > Rolling back</title>
<para > The previous section outlined the basics of how to specify the transactional
settings for the classes, typically service layer classes, in your application in a
declarative fashion. This section describes how you can control the rollback of
transactions in a simple declarative fashion.</para>
<para > The recommended way to indicate to the Spring Framework's
transaction infrastructure that a transaction's work is to be rolled back is to
throw an <exceptionname > Exception</exceptionname> from code that is currently
executing in the context of a transaction. The Spring Framework's
transaction infrastructure code will catch any unhandled
<exceptionname > Exception</exceptionname> as it bubbles up the call stack, and will
mark the transaction for rollback.</para>
<para > Note however that the Spring Framework's transaction infrastructure
code will, by default, <emphasis > only</emphasis> mark a transaction for rollback in
the case of runtime, unchecked exceptions; that is, when the thrown exception is an
instance or subclass of <exceptionname > RuntimeException</exceptionname> .
(<literal > Errors</literal> will also - by default - result in a rollback.) Checked
exceptions that are thrown from a transactional method will
<emphasis > not</emphasis> result in the transaction being rolled back.</para>
<para > Exactly which <exceptionname > Exception</exceptionname> types mark a transaction
for rollback can be configured. Find below a snippet of XML configuration that
demonstrates how one would configure rollback for a checked, application-specific
<exceptionname > Exception</exceptionname> type.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<tx:advice id="txAdvice" transaction-manager="txManager">
2009-03-19 04:00:49 +08:00
<tx:attributes >
<tx:method name= "get*" read-only= "true" ] ] > <lineannotation > <emphasis role= "bold" > rollback-for="NoProductInStockException"</emphasis> </lineannotation> <![CDATA[/>
<tx:method name= "*" />
</tx:attributes>
</tx:advice> ]]></programlisting>
<para > It is also possible to specify 'no rollback rules', for those times when you do
<emphasis > not</emphasis> want a transaction to be marked for rollback when an exception is thrown.
In the example configuration below, we effectively are telling the Spring Framework's transaction
infrastructure to commit the attendant transaction even in the face of an unhandled
<exceptionname > InstrumentNotFoundException</exceptionname> .</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<tx:advice id="txAdvice">
2009-03-19 04:00:49 +08:00
<tx:attributes >
<tx:method name= "updateStock" ] ] > <lineannotation > <emphasis role= "bold" > no-rollback-for="InstrumentNotFoundException"</emphasis> </lineannotation> <![CDATA[/>
<tx:method name= "*" />
</tx:attributes>
</tx:advice> ]]></programlisting>
<para > When the Spring Framework's transaction infrastructure has caught an exception and is consulting
any configured rollback rules to determine whether or not to mark the transaction for rollback, the
<emphasis > strongest</emphasis> matching rule wins. So in the case of the following configuration,
any exception other than an <exceptionname > InstrumentNotFoundException</exceptionname> would result in the
attendant transaction being marked for rollback.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<tx:advice id="txAdvice">
2009-03-19 04:00:49 +08:00
<tx:attributes >
<tx:method name= "*" rollback-for= "Throwable" no-rollback-for= "InstrumentNotFoundException" />
</tx:attributes>
</tx:advice> ]]></programlisting>
<para > The second way to indicate that a rollback is required is to do so
<emphasis > programmatically</emphasis> . Although very simple, this way is quite invasive, and tightly couples
your code to the Spring Framework's transaction infrastructure, as can be seen below:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[public void resolvePosition() {
2009-03-19 04:00:49 +08:00
try {
]]><lineannotation > // some business logic...</lineannotation> < ![CDATA[
} catch (NoProductInStockException ex) {
]]><lineannotation > // trigger rollback programmatically</lineannotation> < ![CDATA[
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}]]></programlisting>
<para > You are strongly encouraged to use the declarative approach to rollback if at all possible.
Programmatic rollback is available should you absolutely need it, but its usage flies in the face of
achieving a nice, clean POJO-based architecture.</para>
</section>
<section id= "transaction-declarative-diff-tx" >
<title > Configuring different transactional semantics for different beans</title>
<para > Consider the scenario where you have a number of service layer objects,
and you want to apply <emphasis > totally different</emphasis> transactional configuration
to each of them. This is achieved by defining distinct <literal > < aop:advisor/> </literal>
elements with differing <literal > 'pointcut'</literal> and <literal > 'advice-ref'</literal>
attribute values.</para>
<para > Let's assume that all of your service layer classes are defined in a root
<literal > 'x.y.service'</literal> package. To make all beans that are instances of classes
defined in that package (or in subpackages) and that have names ending in
<literal > 'Service'</literal> have the default transactional configuration, you would write
the following:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2009-03-19 04:00:49 +08:00
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:config >
<aop:pointcut id= "serviceOperation"
expression="]]><lineannotation > execution(* x.y.service..*Service.*(..))</lineannotation> <![CDATA["/>
<aop:advisor pointcut-ref= "serviceOperation" advice-ref= "txAdvice" />
</aop:config>
]]><lineannotation > < !-- these two beans will be transactional... --> </lineannotation> < ![CDATA[
<bean id= "fooService" class= "x.y.service.DefaultFooService" />
<bean id= "barService" class= "x.y.service.extras.SimpleBarService" />
]]><lineannotation > < !-- ... and these two beans won't --> </lineannotation> < ![CDATA[
<bean id= "anotherService" class= "org.xyz.SomeService" /> ]]><lineannotation > < !-- (not in the right package) --> </lineannotation> < ![CDATA[
<bean id= "barManager" class= "x.y.service.SimpleBarManager" /> ]]><lineannotation > < !-- (doesn't end in 'Service') --> </lineannotation> < ![CDATA[
<tx:advice id= "txAdvice" >
<tx:attributes >
<tx:method name= "get*" read-only= "true" />
<tx:method name= "*" />
</tx:attributes>
</tx:advice>
]]><lineannotation > < !-- other transaction infrastructure beans such as a <interfacename > PlatformTransactionManager</interfacename> omitted... --> </lineannotation> < ![CDATA[
</beans> ]]></programlisting>
<para > Find below an example of configuring two distinct beans with totally different
transactional settings.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2009-03-19 04:00:49 +08:00
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:config >
<aop:pointcut id= "defaultServiceOperation"
expression="]]><lineannotation > execution(* x.y.service.*Service.*(..))</lineannotation> <![CDATA["/>
<aop:pointcut id= "noTxServiceOperation"
expression="]]><lineannotation > execution(* x.y.service.ddl.DefaultDdlManager.*(..))</lineannotation> <![CDATA["/>
<aop:advisor pointcut-ref= "defaultServiceOperation" advice-ref= "defaultTxAdvice" />
<aop:advisor pointcut-ref= "noTxServiceOperation" advice-ref= "noTxAdvice" />
</aop:config>
]]><lineannotation > < !-- this bean will be transactional (see the <literal > 'defaultServiceOperation'</literal> pointcut) --> </lineannotation> < ![CDATA[
<bean id= "fooService" class= "x.y.service.DefaultFooService" />
]]><lineannotation > < !-- this bean will also be transactional, but with totally different transactional settings --> </lineannotation> < ![CDATA[
<bean id= "anotherFooService" class= "x.y.service.ddl.DefaultDdlManager" />
<tx:advice id= "defaultTxAdvice" >
<tx:attributes >
<tx:method name= "get*" read-only= "true" />
<tx:method name= "*" />
</tx:attributes>
</tx:advice>
<tx:advice id= "noTxAdvice" >
<tx:attributes >
<tx:method name= "*" propagation= "NEVER" />
</tx:attributes>
</tx:advice>
]]><lineannotation > < !-- other transaction infrastructure beans such as a <interfacename > PlatformTransactionManager</interfacename> omitted... --> </lineannotation> < ![CDATA[
</beans> ]]></programlisting>
</section>
<section id= "transaction-declarative-txadvice-settings" >
<title > <literal > < tx:advice/> </literal> settings</title>
<para > This section summarises the various transactional settings that can be specified
using the <literal > < tx:advice/> </literal> tag. The default
<literal > < tx:advice/> </literal> settings are:</para>
<para >
<itemizedlist >
<listitem >
<para > The <link linkend= "tx-propagation" > propagation setting</link> is <literal > REQUIRED</literal> </para>
</listitem>
<listitem >
<para > The isolation level is <literal > DEFAULT</literal> </para>
</listitem>
<listitem >
<para > The transaction is read/write</para>
</listitem>
<listitem >
<para > The transaction timeout defaults to the default timeout of the
underlying transaction system, or or none if timeouts are not supported</para>
</listitem>
<listitem >
<para > Any <exceptionname > RuntimeException</exceptionname> will trigger
rollback, and any checked <exceptionname > Exception</exceptionname>
will not</para>
</listitem>
</itemizedlist>
</para>
<para > These default settings can be changed; the various
attributes of the <literal > < tx:method/> </literal> tags that are nested within
<literal > < tx:advice/> </literal> and <literal > < tx:attributes/> </literal>
tags are summarized below:</para>
<para >
<table id= "tx-method-settings" >
<title > <literal > < tx:method/> </literal> settings</title>
<tgroup cols= "4" >
<thead >
<row >
<entry > Attribute</entry>
<entry > Required?</entry>
<entry > Default</entry>
<entry > Description</entry>
</row>
</thead>
<tbody >
<row >
<entry > <literal > name</literal> </entry>
<entry > Yes</entry>
<entry > </entry>
<entry >
<para > The method name(s) with which the transaction attributes
are to be associated. The wildcard (*) character can be used to
associate the same transaction attribute settings with a number
of methods; for example, <literal > 'get*'</literal> ,
<literal > 'handle*'</literal> ,<literal > 'on*Event'</literal> , and so forth.</para>
</entry>
</row>
<row >
<entry > <literal > propagation</literal> </entry>
<entry > No</entry>
<entry > REQUIRED</entry>
<entry > The transaction propagation behavior</entry>
</row>
<row >
<entry > <literal > isolation</literal> </entry>
<entry > No</entry>
<entry > DEFAULT</entry>
<entry > The transaction isolation level</entry>
</row>
<row >
<entry > <literal > timeout</literal> </entry>
<entry > No</entry>
<entry > -1</entry>
<entry > The transaction timeout value (in seconds)</entry>
</row>
<row >
<entry > <literal > read-only</literal> </entry>
<entry > No</entry>
<entry > false</entry>
<entry > Is this transaction read-only?</entry>
</row>
<row >
<entry > <literal > rollback-for</literal> </entry>
<entry > No</entry>
<entry > </entry>
<entry >
<para > The <literal > Exception(s)</literal> that will trigger
rollback; comma-delimited. For example,
<literal > 'com.foo.MyBusinessException,ServletException'</literal> </para>
</entry>
</row>
<row >
<entry > <literal > no-rollback-for</literal> </entry>
<entry > No</entry>
<entry > </entry>
<entry >
<para > The <literal > Exception(s)</literal> that will
<emphasis > not</emphasis> trigger rollback; comma-delimited.
For example,
<literal > 'com.foo.MyBusinessException,ServletException'</literal> </para>
</entry>
</row>
</tbody>
</tgroup>
</table>
2009-04-13 23:04:07 +08:00
</para>
2009-04-13 21:12:38 +08:00
</section>
2009-03-19 04:00:49 +08:00
<section id= "transaction-declarative-annotations" >
<title > Using <interfacename > @Transactional</interfacename> </title>
<note >
<para > The functionality offered by the <interfacename > @Transactional</interfacename>
annotation and the support classes is only available to you if you
are using at least Java 5 (Tiger).</para>
</note>
<para > In addition to the XML-based declarative approach to transaction configuration,
you can also use an annotation-based approach to transaction configuration. Declaring
transaction semantics directly in the Java source code puts the declarations much
closer to the affected code, and there is generally not much danger of undue coupling,
since code that is meant to be used transactionally is almost always deployed that way
anyway.</para>
<para > The ease-of-use afforded by the use of the <interfacename > @Transactional</interfacename>
annotation is best illustrated with an example, after which all of the details
will be explained. Consider the following class definition:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > <lineannotation > // the service class that we want to make transactional</lineannotation> < ![CDATA[
2009-03-19 04:00:49 +08:00
]]><emphasis role= "bold" > @Transactional</emphasis> < ![CDATA[
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
}]]></programlisting>
<para > When the above POJO is defined as a bean in a Spring IoC container, the bean
instance can be made transactional by adding merely <emphasis > one</emphasis> line of
XML configuration, like so:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <lineannotation > < !-- from the file <literal > 'context.xml'</literal> --> </lineannotation> < ![CDATA[
2009-03-19 04:00:49 +08:00
<?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: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.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
]]><lineannotation > < !-- this is the service object that we want to make transactional --> </lineannotation> < ![CDATA[
<bean id= "fooService" class= "x.y.service.DefaultFooService" />
]]><lineannotation > < !-- enable the configuration of transactional behavior based on annotations --> </lineannotation> < ![CDATA[
]]><emphasis role= "bold" > <![CDATA[<tx:annotation-driven transaction-manager="txManager"/>]]> </emphasis> < ![CDATA[
]]><lineannotation > < !-- a <interfacename > PlatformTransactionManager</interfacename> is still required --> </lineannotation> < ![CDATA[
<bean id= "txManager" class= "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
]]><lineannotation > < !-- (this dependency is defined somewhere else) --> </lineannotation> < ![CDATA[
<property name= "dataSource" ref= "dataSource" />
</bean>
]]><lineannotation > < !-- other <literal > < bean/> </literal> definitions here --> </lineannotation> < ![CDATA[
</beans> ]]></programlisting>
<tip >
<para > You can actually omit the <literal > 'transaction-manager'</literal>
attribute in the <literal > < tx:annotation-driven/> </literal> tag
if the bean name of the <interfacename > PlatformTransactionManager</interfacename>
that you want to wire in has the name <literal > 'transactionManager'</literal> .
If the <interfacename > PlatformTransactionManager</interfacename> bean
that you want to dependency inject has any other name, then you have to be
explicit and use the <literal > 'transaction-manager'</literal> attribute as
in the example above.</para>
</tip>
<sidebar >
<title > Method visibility and <interfacename > @Transactional</interfacename> </title>
<para > When using proxies, the <interfacename > @Transactional</interfacename> annotation
should only be applied to methods with <emphasis > public</emphasis> visibility.
If you do annotate protected, private or package-visible methods with the
<interfacename > @Transactional</interfacename> annotation, no error will be raised,
but the annotated method will not exhibit the configured transactional settings.
Consider the use of AspectJ (see below) if you need to annotate non-public methods.</para>
</sidebar>
<para > The <interfacename > @Transactional</interfacename> annotation may be placed
before an interface definition, a method on an interface, a class definition, or a
<emphasis > public</emphasis> method on a class. However, please note that the mere
presence of the <interfacename > @Transactional</interfacename> annotation is not
enough to actually turn on the transactional behavior - the
<interfacename > @Transactional</interfacename> annotation <emphasis > is simply metadata</emphasis>
that can be consumed by something that is <interfacename > @Transactional</interfacename> -aware
and that can use the metadata to configure the appropriate beans with transactional
behavior. In the case of the above example, it is the presence of the
<literal > < tx:annotation-driven/> </literal> element that
<emphasis > switches on</emphasis> the transactional behavior.</para>
<para > The Spring team's recommendation is that you only annotate concrete
classes with the <interfacename > @Transactional</interfacename> annotation,
as opposed to annotating interfaces. You certainly can place the
<interfacename > @Transactional</interfacename> 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
<emphasis > not inherited</emphasis> means that if you are using class-based
proxies (<literal > proxy-target-class="true"</literal> ) or the weaving-based aspect
(<literal > mode="aspectj"</literal> ) then the transaction settings will not be
recognised by the proxying/weaving infrastructure and the object will not be
wrapped in a transactional proxy (which would be decidedly <emphasis > bad</emphasis> ).
So please do take the Spring team's advice and only annotate concrete classes
(and the methods of concrete classes) with the
<interfacename > @Transactional</interfacename> annotation.</para>
<para > <emphasis > Note: In proxy mode (which is the default), only 'external'
method calls coming in through the proxy will be intercepted.</emphasis>
This means that 'self-invocation', i.e. a method within the target object
calling some other method of the target object, won't lead to an actual
transaction at runtime even if the invoked method is marked with
<interfacename > @Transactional</interfacename> !</para>
<para > Consider the use of AspectJ mode (see below) if you expect
self-invocations to be wrapped with transactions as well. In this case,
there won't be a proxy in the first place; instead, the target class
will be 'weaved' (i.e. its byte code will be modified) in order to
turn <interfacename > @Transactional</interfacename> into runtime behavior
on any kind of method.</para>
<para >
<table id= "tx-annotation-driven-settings" >
<title > <literal > < tx:annotation-driven/> </literal> settings</title>
<tgroup cols= "3" >
<thead >
<row >
<entry > Attribute</entry>
<entry > Default</entry>
<entry > Description</entry>
</row>
</thead>
<tbody >
<row >
<entry > <literal > transaction-manager</literal> </entry>
<entry > transactionManager</entry>
<entry > <para > The name of transaction manager to use. Only required
if the name of the transaction manager is not <literal > transactionManager</literal> ,
as in the example above.</para> </entry>
</row>
<row >
<entry > <literal > mode</literal> </entry>
<entry > proxy</entry>
<entry > <para > The default mode "proxy" will process annotated beans
to be proxied using Spring's AOP framework (following proxy semantics,
as discussed above, applying to method calls coming in through the proxy only).
The alternative mode "aspectj" will instead weave the affected classes with
Spring's AspectJ transaction aspect (modifying the target class byte code
in order to apply to any kind of method call).
AspectJ weaving requires spring-aspects.jar on the classpath
as well as load-time weaving (or compile-time weaving) enabled.
(See the section entitled <xref linkend= "aop-aj-ltw-spring" />
for details on how to set up load-time weaving.)</para> </entry>
</row>
<row >
<entry > <literal > proxy-target-class</literal> </entry>
<entry > false</entry>
<entry > <para > Applies to proxy mode only. Controls what type
of transactional proxies are created for classes annotated
with the <interfacename > @Transactional</interfacename> annotation.
If "<literal > proxy-target-class</literal> " attribute is set to
"<literal > true</literal> ", then class-based proxies will be created.
If "<literal > proxy-target-class</literal> " is "<literal > false</literal> "
or if the attribute is omitted, then standard JDK interface-based proxies
will be created. (See the section entitled <xref linkend= "aop-proxying" />
for a detailed examination of the different proxy types.)</para> </entry>
</row>
<row >
<entry > <literal > order</literal> </entry>
<entry > Ordered.LOWEST_PRECEDENCE</entry>
<entry > <para > Defines the order of the transaction advice that will be applied to
beans annotated with <interfacename > @Transactional</interfacename> . More on the
rules related to ordering of AOP advice can be found in the AOP chapter (see section
<xref linkend= "aop-ataspectj-advice-ordering" /> ). Note that not specifying
any ordering will leave the decision as to what order advice is run in to
the AOP subsystem.</para> </entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<note >
<para > The "<literal > proxy-target-class</literal> " attribute on the
<literal > < tx:annotation-driven/> </literal> element controls
what type of transactional proxies are created for classes annotated
with the <interfacename > @Transactional</interfacename> annotation.
If "<literal > proxy-target-class</literal> " attribute is set to
"<literal > true</literal> ", then class-based proxies will be created.
If "<literal > proxy-target-class</literal> " is "<literal > false</literal> "
or if the attribute is omitted, then standard JDK interface-based proxies
will be created. (See the section entitled <xref linkend= "aop-proxying" />
for a detailed examination of the different proxy types.)</para>
</note>
<note >
<para > Note that <literal > < tx:annotation-driven/> </literal> only looks for
<interfacename > @Transactional</interfacename> on beans in the same application context it is defined in.
This means that, if you put <literal > < tx:annotation-driven/> </literal> in a
<interfacename > WebApplicationContext</interfacename> for a <classname > DispatcherServlet</classname> , it only
checks for <interfacename > @Transactional</interfacename> beans in your controllers, and not your services.
See <xref linkend= "mvc-servlet" /> for more information.</para>
</note>
<para > The most derived location takes precedence when evaluating the transactional
settings for a method. In the case of the following example, the
<classname > DefaultFooService</classname> class is annotated at the class level
with the settings for a read-only transaction, but the
<interfacename > @Transactional</interfacename> annotation on the
<methodname > updateFoo(Foo)</methodname> method in the same class takes precedence
over the transactional settings defined at the class level.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[@Transactional(readOnly = true)
2009-03-19 04:00:49 +08:00
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
]]><lineannotation > // do something</lineannotation> < ![CDATA[
}
]]><lineannotation > // <emphasis role= "bold" > these</emphasis> settings have precedence for this method</lineannotation> < ![CDATA[
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
]]><lineannotation > // do something</lineannotation> < ![CDATA[
}
}]]></programlisting>
<section id= "transaction-declarative-attransactional-settings" >
<title > <interfacename > @Transactional</interfacename> settings</title>
<para > The <interfacename > @Transactional</interfacename> annotation is
metadata that specifies that an interface, class, or method must have
transactional semantics; for example, <quote > <emphasis > start a brand new read-only
transaction when this method is invoked, suspending any existing
transaction</emphasis> </quote> . The default
<interfacename > @Transactional</interfacename> settings are:</para>
<itemizedlist >
<listitem >
<para > The propagation setting is <literal > PROPAGATION_REQUIRED</literal> </para>
</listitem>
<listitem >
<para > The isolation level is <literal > ISOLATION_DEFAULT</literal> </para>
</listitem>
<listitem >
<para > The transaction is read/write</para>
</listitem>
<listitem >
<para > The transaction timeout defaults to the default timeout of the
underlying transaction system, or or none if timeouts are not supported</para>
</listitem>
<listitem >
<para > Any <exceptionname > RuntimeException</exceptionname> will trigger
rollback, and any checked <exceptionname > Exception</exceptionname>
will not</para>
</listitem>
</itemizedlist>
<para > These default settings can be changed; the various
properties of the <interfacename > @Transactional</interfacename> annotation
are summarized in the following table:</para>
<para >
<table id= "tx-attransactional-properties" >
<title > <interfacename > @Transactional</interfacename> properties</title>
<tgroup cols= "3" >
<thead >
<row >
<entry > Property</entry>
<entry > Type</entry>
<entry > Description</entry>
</row>
</thead>
<tbody >
<row >
<entry >
<literal > <link linkend= "tx-propagation" > propagation</link> </literal>
</entry>
<entry > enum: <classname > Propagation</classname> </entry>
<entry > optional propagation setting</entry>
</row>
<row >
<entry >
<literal > isolation</literal>
</entry>
<entry > enum: <classname > Isolation</classname> </entry>
<entry > optional isolation level</entry>
</row>
<row >
<entry >
<literal > readOnly</literal>
</entry>
<entry > boolean</entry>
<entry > read/write vs. read-only transaction</entry>
</row>
<row >
<entry >
<literal > timeout</literal>
</entry>
<entry > int (in seconds granularity)</entry>
<entry > the transaction timeout</entry>
</row>
<row >
<entry >
<literal > rollbackFor</literal>
</entry>
<entry > an array of <classname > Class</classname> objects, which
must be derived from <classname > Throwable</classname> </entry>
<entry > an optional array of exception classes which
<emphasis role= "bold" > must</emphasis> cause rollback</entry>
</row>
<row >
<entry >
<literal > rollbackForClassname</literal>
</entry>
<entry > an array of <classname > </classname> class names. Classes
must be derived from <classname > Throwable</classname> </entry>
<entry > an optional array of names of exception classes that
<emphasis role= "bold" > must</emphasis> cause rollback</entry>
</row>
<row >
<entry >
<literal > noRollbackFor</literal>
</entry>
<entry > an array of <classname > Class</classname> objects, which
must be derived from <classname > Throwable</classname> </entry>
<entry > an optional array of exception classes that
<emphasis role= "bold" > must not</emphasis> cause rollback.</entry>
</row>
<row >
<entry >
<literal > noRollbackForClassname</literal>
</entry>
<entry > an array of <classname > String</classname> class names, which
must be derived from <classname > Throwable</classname> </entry>
<entry > an optional array of names of exception classes that
<emphasis role= "bold" > must not</emphasis> cause rollback</entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para > Currently it is not possible to have explicit control over the name of a transaction, where
'name' means the transaction name that will be shown in a transaction monitor, if applicable (for
example, WebLogic's transaction monitor), and in logging output. For declarative transactions, the
transaction name is always the fully-qualified class name + "." + method name of the
transactionally-advised class. For example, if the <methodname > handlePayment(..)</methodname>
method of the <classname > BusinessService</classname> class started a transaction, the name of the
2009-04-13 21:12:38 +08:00
transaction would be: <literal > com.foo.BusinessService.handlePayment</literal> .</para>
2009-03-19 04:00:49 +08:00
</section>
</section>
<section id= "tx-propagation" >
<title > Transaction propagation</title>
<para > <emphasis > Please note that this section of the Spring reference documentation is
<emphasis > not</emphasis> an introduction to transaction propagation proper; rather it details some of the
semantics regarding transaction propagation in Spring.</emphasis> </para>
<para > In the case of Spring-managed transactions, please be aware of the difference between
<emphasis > physical</emphasis> and <emphasis > logical</emphasis> transactions, and how the propagation
setting applies to this difference.</para>
<section id= "tx-propagation-required" >
<title > Required</title>
<para >
<mediaobject >
<imageobject >
<imagedata fileref= "images/tx_prop_required.png" format= "PNG" align= "center" />
</imageobject>
<caption >
<para > PROPAGATION_REQUIRED</para>
</caption>
</mediaobject>
</para>
<para > When the propagation setting is <literal > PROPAGATION_REQUIRED</literal> , a
<emphasis > logical</emphasis> transaction scope is created for each method that it gets applied to. Each
such logical transaction scope can individually decide on rollback-only status, with an outer
transaction scope being logically independent from the inner transaction scope. Of course, in case of
standard <literal > PROPAGATION_REQUIRED</literal> behavior, they will be mapped to the same physical
transaction. So a rollback-only marker set in the inner transaction scope does affect the outer
transactions chance to actually commit (as you would expect it to).</para>
<para > However, in the case where an inner transaction scopes sets the rollback-only marker, the outer
transaction itself has not decided on the rollback itself, and so the rollback (silently triggered by
the inner transaction scope) is unexpected: a corresponding
<classname > UnexpectedRollbackException</classname> will be thrown at that point. This is
<emphasis > expected behavior</emphasis> so that the caller of a transaction can never be misled to assume
that a commit was performed when it really was not. So if an inner transaction (that the outer caller is
not aware of) silently marks a transaction as rollback-only, the outer caller would still innocently
call commit - and needs to receive an <classname > UnexpectedRollbackException</classname> to indicate
clearly that a rollback was performed instead.</para>
</section>
<section id= "tx-propagation-requires_new" >
<title > RequiresNew</title>
<para >
<mediaobject >
<imageobject >
<imagedata fileref= "images/tx_prop_requires_new.png" format= "PNG" align= "center" />
</imageobject>
<caption >
<para > PROPAGATION_REQUIRES_NEW</para>
</caption>
</mediaobject>
</para>
<para > <literal > PROPAGATION_REQUIRES_NEW</literal> , in contrast, uses a <emphasis > completely</emphasis>
independent transaction for each affected transaction scope. In that case, the underlying physical
transactions will be different and hence can commit or rollback independently, with an outer transaction
not affected by an inner transaction's rollback status.</para>
</section>
<section id= "tx-propagation-nested" >
<title > Nested</title>
<para > <literal > PROPAGATION_NESTED</literal> is different again in that it uses a
<emphasis > single</emphasis> physical transaction with multiple savepoints that it can roll back to.
Such partial rollbacks allow an inner transaction scope to trigger a rollback
<emphasis > for its scope</emphasis> , with the outer transaction being able to continue the physical
transaction despite some operations having been rolled back. This is typically mapped onto JDBC
savepoints, so will only work with JDBC resource transactions (see Spring's
<classname > DataSourceTransactionManager</classname> ).</para>
</section>
</section>
<section id= "transaction-declarative-applying-more-than-just-tx-advice" >
<title > Advising transactional operations</title>
<para > Consider the situation where you would like to execute
<emphasis > both</emphasis> transactional <emphasis > and</emphasis>
(to keep things simple) some basic profiling advice. How do you
effect this in the context of using
<literal > < tx:annotation-driven/> </literal> ?</para>
<para > What we want to see when we invoke the <methodname > updateFoo(Foo)</methodname>
method is:</para>
<itemizedlist >
<listitem >
<para > the configured profiling aspect starting up,</para>
</listitem>
<listitem >
<para > then the transactional advice executing,</para>
</listitem>
<listitem >
<para > then the method on the advised object executing</para>
</listitem>
<listitem >
<para > then the transaction committing (we'll assume a sunny day scenario here),</para>
</listitem>
<listitem >
<para > and then finally the profiling aspect reporting (somehow) exactly
how long the whole transactional method invocation took</para>
</listitem>
</itemizedlist>
<note >
<para > This chapter is not concerned with explaining AOP in any great detail
(except as it applies to transactions). Please see the chapter entitled
<xref linkend= "aop" /> for detailed coverage of the various bits and pieces
of the following AOP configuration (and AOP in general).</para>
</note>
<para > Here is the code for a simple profiling aspect. The
ordering of advice is controlled via the <interfacename > Ordered</interfacename>
interface. For full details on advice ordering, see <xref linkend= "aop-ataspectj-advice-ordering" /> .</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[package x.y;
2009-03-19 04:00:49 +08:00
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;
import org.springframework.core.Ordered;
public class SimpleProfiler implements Ordered {
private int order;
]]><lineannotation > // allows us to control the ordering of advice</lineannotation> < ![CDATA[
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
]]><lineannotation > // this method <emphasis > is</emphasis> the around advice</lineannotation> < ![CDATA[
public Object profile(ProceedingJoinPoint call) throws Throwable {
Object returnValue;
StopWatch clock = new StopWatch(getClass().getName());
try {
clock.start(call.toShortString());
returnValue = call.proceed();
} finally {
clock.stop();
System.out.println(clock.prettyPrint());
}
return returnValue;
}
}
]]></programlisting>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2009-03-19 04:00:49 +08:00
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id= "fooService" class= "x.y.service.DefaultFooService" />
]]><lineannotation > < !-- this is the aspect --> </lineannotation> < ![CDATA[
<bean id= "profiler" class= "x.y.SimpleProfiler" >
]]><lineannotation > < !-- execute before the transactional advice (hence the lower order number) --> </lineannotation> < ![CDATA[
<property name= "order" ] ] > <emphasis role= "bold" > value="1"</emphasis> <![CDATA[/>
</bean>
<tx:annotation-driven transaction-manager= "txManager" ] ] > <emphasis role= "bold" > order="200"</emphasis> <![CDATA[/>
<aop:config >
]]><lineannotation > < !-- this advice will execute <emphasis role= "bold" > around</emphasis> the transactional advice --> </lineannotation> < ![CDATA[
<aop:aspect id= "profilingAspect" ref= "profiler" >
<aop:pointcut id= "serviceMethodWithReturnValue"
expression="execution(!void x.y..*Service.*(..))"/>
<aop:around method= "profile" pointcut-ref= "serviceMethodWithReturnValue" />
</aop:aspect>
</aop:config>
<bean id= "dataSource" class= "org.apache.commons.dbcp.BasicDataSource" destroy-method= "close" >
<property name= "driverClassName" value= "oracle.jdbc.driver.OracleDriver" />
<property name= "url" value= "jdbc:oracle:thin:@rj-t42:1521:elvis" />
<property name= "username" value= "scott" />
<property name= "password" value= "tiger" />
</bean>
<bean id= "txManager" class= "org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name= "dataSource" ref= "dataSource" />
</bean>
</beans> ]]></programlisting>
<para > The result of the above configuration will be a <literal > 'fooService'</literal>
bean that has profiling and transactional aspects applied to it
<emphasis > in that order</emphasis> . The configuration of any number of additional
aspects is effected in a similar fashion.</para>
<para > Finally, find below some example configuration for effecting the same
setup as above, but using the purely XML declarative approach.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > <![CDATA[<?xml version="1.0" encoding="UTF-8"?>
2009-03-19 04:00:49 +08:00
<beans xmlns= "http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<bean id= "fooService" class= "x.y.service.DefaultFooService" />
]]><lineannotation > < !-- the profiling advice --> </lineannotation> < ![CDATA[
<bean id= "profiler" class= "x.y.SimpleProfiler" >
]]><lineannotation > < !-- execute before the transactional advice (hence the lower order number) --> </lineannotation> < ![CDATA[
]]><emphasis role= "bold" > < property name="order" value="1</emphasis> <![CDATA["/>
</bean>
<aop:config >
<aop:pointcut id= "entryPointMethod" expression= "execution(* x.y..*Service.*(..))" />
]]><lineannotation > < !-- will execute after the profiling advice (c.f. the order attribute) --> </lineannotation> < ![CDATA[
<aop:advisor
advice-ref="txAdvice"
pointcut-ref="entryPointMethod"
]]><emphasis role= "bold" > order="2</emphasis> "/> <lineannotation > < !-- order value is higher than the profiling aspect --> </lineannotation> < ![CDATA[
<aop:aspect id= "profilingAspect" ref= "profiler" >
<aop:pointcut id= "serviceMethodWithReturnValue"
expression="execution(!void x.y..*Service.*(..))"/>
<aop:around method= "profile" pointcut-ref= "serviceMethodWithReturnValue" />
</aop:aspect>
</aop:config>
<tx:advice id= "txAdvice" transaction-manager= "txManager" >
<tx:attributes >
<tx:method name= "get*" read-only= "true" />
<tx:method name= "*" />
</tx:attributes>
</tx:advice>
]]><lineannotation > < !-- other < bean/> definitions such as a <interfacename > DataSource</interfacename> and a <interfacename > PlatformTransactionManager</interfacename> here --> </lineannotation> < ![CDATA[
</beans> ]]></programlisting>
<para > The result of the above configuration will be a <literal > 'fooService'</literal>
bean that has profiling and transactional aspects applied to it
<emphasis > in that order</emphasis> . If we wanted the profiling advice to execute
<emphasis > after</emphasis> the transactional advice on the way in, and
<emphasis > before</emphasis> the transactional advice on the way out, then we would
simply swap the value of the profiling aspect bean's <literal > 'order'</literal>
property such that it was higher than the transactional advice's order value.</para>
<para > The configuration of any number of additional aspects is achieved in a
similar fashion.</para>
</section>
<section id= "transaction-declarative-aspectj" >
<title > Using <interfacename > @Transactional</interfacename> with AspectJ</title>
<para > It is also possible to use the Spring Framework's
<interfacename > @Transactional</interfacename> support outside of a Spring container
by means of an AspectJ aspect. To use this support you must first
annotate your classes (and optionally your classes' methods with the
<interfacename > @Transactional</interfacename> annotation, and then you must link
(weave) your application with the
<classname > org.springframework.transaction.aspectj.AnnotationTransactionAspect</classname>
defined in the <filename class= "libraryfile" > spring-aspects.jar</filename> file.
The aspect must also be configured with a transaction manager. You could of course
use the Spring Framework's IoC container to take care of dependency injecting the
aspect. The simplest way to
configure the transaction management aspect is to use the
<literal > '< tx:annotation-driven/> '</literal> element and specify the
<literal > mode</literal> attribute to <literal > asepctj</literal> as described in
<xref linkend= "transaction-declarative-annotations" /> .
Since we're focusing here on applications running outside of a Spring
container, we'll show you how to do it programmatically.</para>
<note >
<para > Prior to continuing, you may well want to read the previous sections entitled
<xref linkend= "transaction-declarative-annotations" /> and <xref linkend= "aop" />
respectively.</para>
</note>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > <lineannotation > // construct an appropriate transaction manager </lineannotation> < ![CDATA[
2009-03-19 04:00:49 +08:00
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());
]]><lineannotation > // configure the <classname > AnnotationTransactionAspect</classname> to use it; this must be done before executing any transactional methods</lineannotation> < ![CDATA[
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager); ]]></programlisting>
<note >
<para > When using this aspect, you must annotate the <emphasis > implementation</emphasis>
class (and/or methods within that class), <emphasis > not</emphasis> the interface
(if any) that the class implements. AspectJ follows Java's rule that annotations on
interfaces are <emphasis > not inherited</emphasis> .</para>
</note>
<para > The <interfacename > @Transactional</interfacename> annotation on a class specifies
the default transaction semantics for the execution of any method in the class.</para>
<para > The <interfacename > @Transactional</interfacename> annotation on a method within
the class overrides the default transaction semantics given by the class annotation
(if present). Any method may be annotated, regardless of visibility.</para>
<para > To weave your applications with the <classname > AnnotationTransactionAspect</classname>
you must either build your application with AspectJ (see the
<ulink url= "http://www.eclipse.org/aspectj/doc/released/devguide/index.html" > AspectJ Development Guide</ulink> )
or use load-time weaving. See the section entitled <xref linkend= "aop-aj-ltw" /> for a
discussion of load-time weaving with AspectJ.</para>
</section>
</section>
<section id= "transaction-programmatic" >
<title > Programmatic transaction management</title>
<para > The Spring Framework provides two means of programmatic transaction management:</para>
<itemizedlist >
<listitem >
<para > Using the <classname > TransactionTemplate</classname> .</para>
</listitem>
<listitem >
<para > Using a <interfacename > PlatformTransactionManager</interfacename>
implementation directly.</para>
</listitem>
</itemizedlist>
<para > If you are going to use programmatic transaction management, the Spring
team generally recommends using the <classname > TransactionTemplate</classname> .
The second approach is similar to using the JTA <interfacename > UserTransaction</interfacename>
API (although exception handling is less cumbersome).</para>
<section id= "tx-prog-template" >
<title > Using the <classname > TransactionTemplate</classname> </title>
<para > The <classname > TransactionTemplate</classname> adopts the same
approach as other Spring <emphasis > templates</emphasis> such as the
<classname > JdbcTemplate</classname> . It uses a callback approach, to
free application code from having to do the boilerplate acquisition
and release of transactional resources, and results in code that is
intention driven, in that the code that is written focuses solely
on what the developer wants to do.</para>
<note >
<para > As you will immediately see in the examples that follow, using
the <classname > TransactionTemplate</classname> absolutely
couples you to Spring's transaction infrastructure and APIs.
Whether or not programmatic transaction management is suitable
for your development needs is a decision that you will have to
make yourself.</para>
</note>
<para > Application code that must execute in a transactional context,
and that will use the <classname > TransactionTemplate</classname> explicitly,
looks like this. You, as an application developer, will write a
<interfacename > TransactionCallback</interfacename> implementation (typically
expressed as an anonymous inner class) that will contain all of the code
that you need to have execute in the context of a transaction. You will then
pass an instance of your custom <interfacename > TransactionCallback</interfacename>
to the <methodname > execute(..)</methodname> method exposed on the
<classname > TransactionTemplate</classname> . </para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[public class SimpleService implements Service {
2009-03-19 04:00:49 +08:00
]]><lineannotation > // single <classname > TransactionTemplate</classname> shared amongst all methods in this instance</lineannotation> < ![CDATA[
private final TransactionTemplate transactionTemplate;
]]><lineannotation > // use constructor-injection to supply the <interfacename > PlatformTransactionManager</interfacename> </lineannotation> < ![CDATA[
public SimpleService(PlatformTransactionManager transactionManager) {
Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
this.transactionTemplate = new TransactionTemplate(transactionManager);
}
public Object someServiceMethod() {
return transactionTemplate.execute(new TransactionCallback() {
]]><lineannotation > // the code in this method executes in a transactional context</lineannotation> < ![CDATA[
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
}]]></programlisting>
<para > If there is no return value, use the convenient
<classname > TransactionCallbackWithoutResult</classname> class via an
anonymous class like so:</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > <![CDATA[transactionTemplate.execute(new ]]> <emphasis role= "bold" > TransactionCallbackWithoutResult</emphasis> < ![CDATA[() {
2009-03-19 04:00:49 +08:00
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
});]]></programlisting>
<para > Code within the callback can roll the transaction back by calling
the <literal > setRollbackOnly()</literal> method on the supplied
<interfacename > TransactionStatus</interfacename> object.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[transactionTemplate.execute(new TransactionCallbackWithoutResult() {
2009-03-19 04:00:49 +08:00
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessExeption ex) {
]]><emphasis role= "bold" > status.setRollbackOnly();</emphasis> < ![CDATA[
}
}
});]]></programlisting>
<section id= "tx-prog-template-settings" >
<title > Specifying transaction settings</title>
<para > Transaction settings such as the propagation mode, the isolation level,
the timeout, and so forth can be set on the <classname > TransactionTemplate</classname>
either programmatically or in configuration. <classname > TransactionTemplate</classname>
instances by default have the <link linkend= "transaction-declarative-txadvice-settings" > default transactional settings</link> .
Find below an example of programmatically customizing the
transactional settings for a specific <classname > TransactionTemplate</classname> .
</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[public class SimpleService implements Service {
2009-03-19 04:00:49 +08:00
private final TransactionTemplate transactionTemplate;
public SimpleService(PlatformTransactionManager transactionManager) {
Assert.notNull(transactionManager, "The 'transactionManager' argument must not be null.");
this.transactionTemplate = new TransactionTemplate(transactionManager);
]]><lineannotation > // the transaction settings can be set here explicitly if so desired</lineannotation> < ![CDATA[
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
this.transactionTemplate.setTimeout(30); ]]><lineannotation > // 30 seconds</lineannotation> < ![CDATA[
]]><lineannotation > // and so forth...</lineannotation> < ![CDATA[
}
}]]></programlisting>
<para > Find below an example of defining a <classname > TransactionTemplate</classname> with some custom
transactional settings, using Spring XML configuration. The '<literal > sharedTransactionTemplate</literal> '
can then be injected into as many services as are required.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "xml" > < ![CDATA[<bean id= "sharedTransactionTemplate"
2009-03-19 04:00:49 +08:00
class="org.springframework.transaction.support.TransactionTemplate">
<property name= "isolationLevelName" value= "ISOLATION_READ_UNCOMMITTED" />
<property name= "timeout" value= "30" />
</bean> "]]></programlisting>
</section>
<para >
Finally, instances of the <classname > TransactionTemplate</classname> class are
threadsafe, in that instances do not maintain any conversational state.
<classname > TransactionTemplate</classname> instances <emphasis > do</emphasis>
however maintain configuration state, so while a number of classes
may choose to share a single instance of a <classname > TransactionTemplate</classname> , if a class needed
to use a <classname > TransactionTemplate</classname> with different settings
(for example, a different isolation level), then two distinct
<classname > TransactionTemplate</classname> instances would need to be
created and used.
</para>
</section>
<section id= "transaction-programmatic-ptm" >
<title > Using the <interfacename > PlatformTransactionManager</interfacename> </title>
<para > You can also use the
<interfacename > org.springframework.transaction.PlatformTransactionManager</interfacename>
directly to manage your transaction. Simply pass the implementation of
the <interfacename > PlatformTransactionManager</interfacename> you're
using to your bean via a bean reference. Then, using the
<interfacename > TransactionDefinition</interfacename> and
<interfacename > TransactionStatus</interfacename> objects you can
initiate transactions, rollback and commit.</para>
2009-04-13 21:12:38 +08:00
<programlisting language= "java" > < ![CDATA[DefaultTransactionDefinition def = new DefaultTransactionDefinition();
2009-03-19 04:00:49 +08:00
]]><lineannotation > // explicitly setting the transaction name is something that can only be done programmatically</lineannotation> < ![CDATA[
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
]]><lineannotation > // execute your business logic here</lineannotation> < ![CDATA[
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
txManager.commit(status);]]></programlisting>
</section>
</section>
<section id= "tx-decl-vs-prog" >
<title > Choosing between programmatic and declarative transaction management</title>
<para > Programmatic transaction management is usually a good idea only if
you have a small number of transactional operations. For example, if you
have a web application that require transactions only for certain update
operations, you may not want to set up transactional proxies using Spring
or any other technology. In this case, using the <classname > TransactionTemplate</classname>
<emphasis > may</emphasis> be a good approach. Being able to set the transaction name
explicitly is also something that can only be done using the programmatic
approach to transaction management.</para>
<para > On the other hand, if your application has numerous transactional
operations, declarative transaction management is usually worthwhile. It
keeps transaction management out of business logic, and is not difficult
to configure. When using the Spring Framework, rather than EJB CMT, the
configuration cost of declarative transaction management is greatly reduced.</para>
</section>
<section id= "transaction-application-server-integration" >
<title > Application server-specific integration</title>
<para > Spring's transaction abstraction generally is application server
agnostic. Additionally, Spring's <classname > JtaTransactionManager</classname> class,
which can optionally perform a JNDI lookup for the JTA
<interfacename > UserTransaction</interfacename> and
<interfacename > TransactionManager</interfacename> objects, autodetects
the location for the latter object, which varies by application server. Having
access to the JTA <interfacename > TransactionManager</interfacename> allows for
enhanced transaction semantics, in particular supporting transaction suspension.
Please see the <classname > JtaTransactionManager</classname> Javadocs for details.
</para>
<para > Spring's <classname > JtaTransactionManager</classname> is the standard
choice when running on J2EE application servers, known to work on all common
servers. Its advanced functionality such as transaction suspension is known to
work on many servers as well - including GlassFish, JBoss, Geronimo and Oracle
OC4J - without any special configuration required. However, for fully supported
transaction suspension and further advanced integration, Spring ships special
adapters for IBM WebSphere and BEA WebLogic and also for Oracle OC4J.
We'll discuss these adapters in the following sections.</para>
<para > <emphasis > For standard scenarios, including WebLogic, WebSphere and OC4J,
consider using the convenient <literal > '< tx:jta-transaction-manager/> '</literal>
configuration element.</emphasis> This will automatically detect the underlying
server and choose the best transaction manager available for the platform.
This means that you won't have to configure server-specific adapter classes
(as discussed in the following sections) explicitly; they will rather be chosen
automatically, with the standard <classname > JtaTransactionManager</classname>
as default fallback.</para>
<section id= "transaction-application-server-integration-websphere" >
<title > IBM WebSphere</title>
<para > On WebSphere 6.0 and above, the recommended Spring JTA transaction
manager to use is <classname > WebSphereUowTransactionManager</classname> .
This special adapter leverages IBM's <interfacename > UOWManager</interfacename>
API which is available in WebSphere Application Server 6.0.2.19 or above
and 6.1.0.9 or above. With this adapter, Spring-driven transaction suspension
(suspend/resume as initiated by <literal > PROPAGATION_REQUIRES_NEW</literal> )
is officially supported by IBM!</para>
<para > In a WebSphere 5.1 environment, you may wish to use
Spring's <classname > WebSphereTransactionManagerFactoryBean</classname>
class. This is a factory bean which retrieves the JTA
<interfacename > TransactionManager</interfacename> in a WebSphere environment, which
is done via WebSphere's <literal > static</literal> access methods.
Once the JTA <interfacename > TransactionManager</interfacename> instance has
been obtained via this factory bean, Spring's
<classname > JtaTransactionManager</classname> may be configured with a
reference to it, for enhanced transaction semantics over the use of only
the JTA <interfacename > UserTransaction</interfacename> object.
Please see the Javadocs for full details.</para>
<para > <emphasis > Note that <classname > WebSphereTransactionManagerFactoryBean</classname>
usage is known to work on WAS 5.1 and 6.0 but is not officially supported
by IBM.</emphasis> Prefer <classname > WebSphereUowTransactionManager</classname>
when running on WAS 6.0 or higher (see above).</para>
</section>
<section id= "transaction-application-server-integration-weblogic" >
<title > BEA WebLogic</title>
<para > On WebLogic 8.1 or above, you will generally prefer to use
the <classname > WebLogicJtaTransactionManager</classname> instead
of the stock <classname > JtaTransactionManager</classname> class.
This special WebLogic-specific subclass of the normal
<classname > JtaTransactionManager</classname> supports the full power of
Spring's transaction definitions in a WebLogic-managed transaction environment,
beyond standard JTA semantics: Features include transaction names, per-transaction
isolation levels, and proper resuming of transactions in all cases.</para>
</section>
<section id= "transaction-application-server-integration-oc4j" >
<title > Oracle OC4J</title>
<para > Spring ships a special adapter class for OC4J 10.1.3 or above:
<classname > OC4JJtaTransactionManager</classname> . This is analogous to
the <classname > WebLogicJtaTransactionManager</classname> class discussed
in the previous section, providing similar value-adds on OC4J:
transaction names and per-transaction isolation levels.</para>
<para > Note that the full JTA functionality, including transaction suspension,
works fine with Spring's <classname > JtaTransactionManager</classname> on
OC4J as well. The special <classname > OC4JJtaTransactionManager</classname>
adapter simply provides value-adds beyond standard JTA.</para>
</section>
</section>
<section id= "transaction-solutions-to-common-problems" >
<title > Solutions to common problems</title>
<section id= "transaction-solutions-to-common-problems-wrong-ptm" >
<title > Use of the wrong transaction manager for a specific <interfacename > DataSource</interfacename> </title>
<para > You should take care to use the <emphasis > correct</emphasis>
<interfacename > PlatformTransactionManager</interfacename>
implementation for their requirements. Used properly, the Spring Framework
merely provides a straightforward and portable abstraction. If you are using
global transactions, you <emphasis > must</emphasis> use the
<classname > org.springframework.transaction.jta.JtaTransactionManager</classname> class
(or an
<link linkend= "transaction-application-server-integration" > application server-specific subclass</link>
of it) for all your transactional operations. Otherwise the transaction infrastructure
will attempt to perform local transactions on resources such as container
<interfacename > DataSource</interfacename> instances. Such local transactions
do not make sense, and a good application server will treat them as errors.</para>
</section>
</section>
<section id= "transaction-resources" >
<title > Further Resources</title>
<para > Find below links to further resources about the Spring Framework's transaction support.</para>
<itemizedlist >
<listitem >
<para > <ulink url= "http://www.infoq.com/minibooks/JTDS" > Java Transaction Design Strategies</ulink>
is a book available from <ulink url= "http://www.infoq.com/" > InfoQ</ulink> that provides a well-paced
introduction to transactions in Java. It also includes side-by-side examples of how to configure and use
transactions using both the Spring Framework and EJB3.</para>
</listitem>
</itemizedlist>
</section>
</chapter>