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-06-26 11:37:18 +08:00
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
2009-03-19 04:00:49 +08:00
<chapter id= "transaction" >
2009-07-31 02:29:56 +08:00
<title > Transaction Management</title>
2009-03-19 04:00:49 +08:00
<section id= "transaction-intro" >
2009-07-31 02:29:56 +08:00
<title > Introduction to Spring Framework transaction management</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > Comprehensive transaction support is among the most compelling
reasons to use Spring Framework. Spring Framework provides a consistent
abstraction for transaction management that delivers the following
benefits:</para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<itemizedlist >
<listitem >
2009-07-31 02:29:56 +08:00
<para > Consistent programming model across different transaction APIs
such as Java Transaction API (JTA), JDBC, Hibernate, Java Persistence
API (JPA), and Java Data Objects (JDO).</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Support for <link linkend= "transaction-declarative" > declarative
2009-06-26 11:37:18 +08:00
transaction management</link> .</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Simpler API for <link
2009-06-26 11:37:18 +08:00
linkend="transaction-programmatic">programmatic</link> transaction
2009-07-31 02:29:56 +08:00
management than complex transaction APIs such as JTA.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Excellent integration with Spring's data access
2009-06-26 11:37:18 +08:00
abstractions.</para>
2009-03-19 04:00:49 +08:00
</listitem>
</itemizedlist>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > The following sections describe Spring Framework's transaction
value-adds and technologies. (The chapter also includes discussions of
best practices, application server integration, and solutions to common
problems.)</para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<itemizedlist >
<listitem >
2009-07-31 02:29:56 +08:00
<para > <link linkend= "transaction-motivation" > Advantages of Spring
Framework's transaction support model</link> describes
<emphasis > why</emphasis> you would use Spring Framework's transaction
abstraction instead of EJB Container-Managed Transactions (CMT) or
choosing to drive transactions through a proprietary API such as
Hibernate.</para>
<!-- The section (formerly called Motivation) does not mention Hibernate. It talks about local and global. -->
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > <link linkend= "transaction-strategies" > Understanding the Spring
Framework transaction abstraction</link> outlines the core classes and
describes how to configure and obtain
<interfacename > DataSource</interfacename> instances from a variety of
sources.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > <link linkend= "tx-resource-synchronization" > Synchronizing
resources with transactions </link> describes how the application code
ensures that resources are created, reused, and cleaned up
properly.<!-- Added above link and bullet item. --> </para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > <link linkend= "transaction-declarative" > Declarative transaction
management</link> describes support for declarative transaction
2009-06-26 11:37:18 +08:00
management.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-07-31 02:29:56 +08:00
<listitem >
<para > <link linkend= "transaction-programmatic" > Programmatic
transaction management</link> covers support for programmatic (that
is, explicitly coded) transaction management.</para>
</listitem>
2009-03-19 04:00:49 +08:00
</itemizedlist>
</section>
<section id= "transaction-motivation" >
2009-07-31 02:29:56 +08:00
<title > Advantages of Spring Framework's transaction support model<!-- Renamed section to make it more to the point. --> </title>
<para > Traditionally, Java EE developers have had two choices for
transaction management: <emphasis > global</emphasis> or
<emphasis > local</emphasis> transactions, both of which have profound
limitations. Global and local transaction management is reviewed in the
next two sections, followed by a discussion of how Spring Framework's
transaction management support addresses the limitations of the global and
local transaction models.</para>
<!-- Gave global, local, and spring models their own sections. These need to be called out at a higher level, esp. Spring advantage! -->
<section >
<title > Global transactions</title>
<para > Global transactions enable you to work with multiple transactional
resources, typically relational databases and message queues. The
application server manages global transactions through the JTA, which 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 you
<emphasis > also</emphasis> need to use JNDI in order to use JTA.
Obviously the use of global transactions would limit any potetntial
reuse of application code, as JTA is normally only available in an
application server environment.</para>
2009-06-26 11:37:18 +08:00
<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
2009-07-31 02:29:56 +08:00
JNDI lookups, although of course the use of EJB itself necessitates the
use of JNDI. It removes most but not all of the need 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 of 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>
</section>
<section >
<title > Local transactions</title>
<para > Local transactions are resource-specific, such as a transaction
associated with a JDBC connection. 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. Because the application server is not involved in
transaction management, it cannot help ensure correctness across
multiple resources. (It is worth noting that most applications use a
single transaction resource.) Another downside is that local
transactions are invasive to the programming model.</para>
</section>
<section >
<title > Spring Framework's consistent programming model</title>
<para > Spring resolves the disadvantages of global and local
transactions. 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. Spring Framework provides both declarative and
programmatic transaction management. Most users prefer declarative
transaction management, which is recommended in most cases.</para>
<!-- Do you need to specify that Spring allows you to work with *multiple* transactional resourcess (as global transactions do)? -->
<para > With programmatic transaction management, developers work with the
Spring Framework transaction abstraction, which can run over any
underlying transaction infrastructure. <!-- Re preceding statement, does this mean that next section re transaction abstraction applies only to programmatic tx management?If so --> <!-- shouldn't the next section be subsection of *Programmatic transaction management* section? However, there is a sentence in the next --> <!-- section that reads *regardless of whether you opt for declarative or prog. tx man. defining correct PlatformTransactionManager impl. is --> <!-- absolutely essential.* This is followed by discussion of that impl. So I'm not sure what goes where.
TR: I think it's fine as is - the concepts apply to both programmatic and declarative transactions
-->With the preferred declarative model, developers typically write little or
no code related to transaction management, and hence do not depend on
the Spring Framework transaction API, or any other transaction
API.</para>
<sidebar >
<title > Do you need an application server for transaction
management?</title>
<para > Spring Framework's transaction management support changes
traditional rules as to when a Java EE application requires an
application server.</para>
<para > In particular, you do not need an application server simply for
declarative transactions through EJBs. In fact, even if your
application server has powerful JTA capabilities, you may decide that
the Spring Framework's declarative transactions offer more power and a
more productive programming model than EJB CMT.</para>
<para > Typically you need an application server's JTA capability only
if your application needs to handle transactions across multiple
resources, which is not a requirement for many applications. Many
high-end applications use a single, highly scalable database (such as
Oracle RAC) instead. 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 Java Message Service (JMS) and J2EE Connector Architecture
(JCA).</para>
<para > Spring Framework <emphasis > gives you the choice of when to scale
your application to a fully loaded application server</emphasis> . Gone
are the days when the only alternative to using EJB CMT or JTA was to
write code with local transactions such as those on JDBC connections,
and face a hefty rework if you need that code to run within global,
container-managed transactions. With Spring Framework, only some of
the bean definitions in your configuration file, rather than your
code, needs to change.</para>
<!-- CLarify last sentence. Only what kind of configuration has to change?
TR: changed to say "some of the bean definitions in your configuration file"-->
</sidebar>
</section>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-strategies" >
2009-07-31 02:29:56 +08:00
<title > Understanding the Spring Framework transaction abstraction<!-- If this section applies only to prog. tx management, we should say that up front. Add info? TR: It's relevant for declarative tx as well --> </title>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<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>
2009-07-31 02:29:56 +08:00
interface:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > 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;
2009-06-26 11:37:18 +08:00
}</programlisting>
2009-07-31 02:29:56 +08:00
<para > This is primarily a service provider interface (SPI), although it
can be used <link
linkend="transaction-programmatic-ptm">programmatically</link> from your
application code. <!-- Write out SPI with SPI in parentheses. SPI stands for a number of different things.And does logic of sentence make sense?
TR: spelled SPI out and added a bit of clarification at the end-->Because
2009-06-26 11:37:18 +08:00
<interfacename > PlatformTransactionManager</interfacename> is an
2009-07-31 02:29:56 +08:00
<emphasis > interface</emphasis> , it can be easily mocked or stubbed as
necessary. It is not tied to a lookup strategy such as JNDI.
2009-03-19 04:00:49 +08:00
<interfacename > PlatformTransactionManager</interfacename> implementations
2009-07-31 02:29:56 +08:00
are defined like any other object (or bean) in the Spring Framework IoC
container. This benefit alone makes Spring Framework transactions a
worthwhile abstraction even when you work with JTA. Transactional code can
be tested much more easily than if it used JTA directly.</para>
2009-06-26 11:37:18 +08:00
<para > Again in keeping with Spring's philosophy, the
<exceptionname > TransactionException</exceptionname> that can be thrown by
any of the <interfacename > PlatformTransactionManager</interfacename>
2009-07-31 02:29:56 +08:00
interface's methods is <emphasis > unchecked</emphasis> (that is, it extends
2009-06-26 11:37:18 +08:00
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
2009-03-19 04:00:49 +08:00
that developers are not <emphasis > forced</emphasis> to do so.</para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<para > The <methodname > getTransaction(..)</methodname> method returns a
<interfacename > TransactionStatus</interfacename> object, depending on a
2009-06-26 11:37:18 +08:00
<interfacename > TransactionDefinition</interfacename> parameter. The
returned <interfacename > TransactionStatus</interfacename> might represent
2009-07-31 02:29:56 +08:00
a new transaction, or can represent an existing transaction if a matching
transaction exists in the current call stack. The implication in this
latter case is that, as with Java EE transaction contexts, a
<interfacename > TransactionStatus</interfacename> is associated with a
<emphasis role= "bold" > thread</emphasis> of execution.<!-- Previous sentences were difficult to follow because of all the parenthetical phrases.Revise if necessary. --> </para>
2009-06-26 11:37:18 +08:00
<para > The <interfacename > TransactionDefinition</interfacename> interface
specifies:</para>
2009-03-19 04:00:49 +08:00
<itemizedlist >
<listitem >
2009-07-31 02:29:56 +08:00
<para > <emphasis role= "bold" > Isolation</emphasis> : The degree to which
this transaction is isolated from the work of other transactions. For
example, can this transaction see uncommitted writes from other
2009-06-26 11:37:18 +08:00
transactions?</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > <emphasis role= "bold" > Propagation</emphasis> : Typically, all
code executed within a transaction scope will run in that transaction.
However, you have options for specifying behavior in the event that a
2009-06-26 11:37:18 +08:00
transactional method is executed when a transaction context already
2009-07-31 02:29:56 +08:00
exists. <!-- Correct to say you have options? A human has to specify what the behavior will be, right? --> For
example, code can continue running in the existing transaction (the
common case); or the existing transaction can be suspended and a new
transaction created. <emphasis > Spring offers all of the transaction
propagation options familiar from EJB CMT</emphasis> . To read about
the semantics of transaction propagation in Spring, see <xref
2009-06-26 11:37:18 +08:00
linkend="tx-propagation" />.</para>
</listitem>
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > <emphasis role= "bold" > Timeout</emphasis> : How long this
transaction runs before timing out and being rolled back automatically
by the underlying transaction infrastructure.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > <emphasis role= "bold" > Read-only status</emphasis> : A read-only
transaction<!-- describes status but (TR: this was a bit confusing; it read better the original way)
we could say 'reads but does not modify' --> does not modify any data.
Read-only transactions can be a useful optimization in some cases,
such as when you are using Hibernate.<!-- I added that it describes status. OK? Elaborate on purpose? --> </para>
2009-03-19 04:00:49 +08:00
</listitem>
</itemizedlist>
2009-06-26 11:37:18 +08:00
<para > These settings reflect standard transactional concepts. If
2009-07-31 02:29:56 +08:00
necessary, refer to resources that discuss transaction isolation levels
and other core transaction concepts. Understanding these concepts is
essential to using the Spring Framework or any transaction management
solution.</para>
2009-06-26 11:37:18 +08:00
<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>
<programlisting language= "java" > public interface TransactionStatus extends SavepointManager {
2009-03-19 04:00:49 +08:00
2009-05-16 04:15:18 +08:00
boolean isNewTransaction();
2009-03-19 04:00:49 +08:00
2009-05-16 04:15:18 +08:00
boolean hasSavepoint();
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
boolean isCompleted();
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
}</programlisting>
<para > Regardless of whether you opt for declarative or programmatic
transaction management in Spring, defining the correct
<interfacename > PlatformTransactionManager</interfacename> implementation
2009-07-31 02:29:56 +08:00
is absolutely essential. You typically define this implementation through
dependency injection.</para>
<!-- Do you need a link to an explanation of DI?
TR: at this point in the text, I don't think you would need that
-->
2009-06-26 11:37:18 +08:00
<para > <interfacename > PlatformTransactionManager</interfacename>
implementations normally require knowledge of the environment in which
2009-07-31 02:29:56 +08:00
they work: JDBC, JTA, Hibernate, and so on. The following examples show
how you can define a local
<interfacename > PlatformTransactionManager</interfacename> implementation.
(This example works with plain JDBC.)</para>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > You define a JDBC <interfacename > DataSource</interfacename> </para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
< 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>
2009-07-31 02:29:56 +08:00
<para > The related <interfacename > The
PlatformTransactionManager</interfacename> bean definition will then have
a reference to the <interfacename > DataSource</interfacename> definition.
It will look like this:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
< property name="dataSource" ref="dataSource"/>
< /bean> </programlisting>
2009-07-31 02:29:56 +08:00
<para > If you use JTA in a Java EE container then you use a container
<interfacename > DataSource</interfacename> , obtained through JNDI, in
conjunction with Spring's <classname > JtaTransactionManager</classname> .
This is what the JTA and JNDI lookup version would look like:</para>
<!-- Indicate what the following example demonstrates.What is its purpose? -->
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
2009-03-19 04:00:49 +08:00
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jee="http://www.springframework.org/schema/jee"
2009-05-16 04:15:18 +08:00
xsi:schemaLocation="
http://www.springframework.org/schema/beans
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/jee
2009-06-26 11:37:18 +08:00
http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< jee:jndi-lookup id="dataSource" jndi-name="jdbc/jpetstore"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager" />
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- other <literal > < bean/> </literal> definitions here --> </lineannotation>
< /beans> </programlisting>
2009-03-19 04:00:49 +08:00
2009-07-31 02:29:56 +08:00
<para > The <classname > JtaTransactionManager</classname> does not need to
know about the <interfacename > DataSource</interfacename> , or any other
specific resources, because it uses the container's global transaction
management infrastructure.</para>
2009-03-19 04:00:49 +08:00
<note >
2009-07-31 02:29:56 +08:00
<para > The above definition of the <literal > dataSource</literal> bean
2009-06-26 11:37:18 +08:00
uses the <literal > < jndi-lookup/> </literal> tag from the
2009-07-31 02:29:56 +08:00
<literal > jee</literal> namespace. For more information on schema-based
2009-06-26 11:37:18 +08:00
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>
2009-03-19 04:00:49 +08:00
</note>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > You can also use Hibernate local transactions easily, as shown in
the following examples. In this case, you need to define a Hibernate
<classname > LocalSessionFactoryBean</classname> , which your application
code will use to obtain Hibernate <interfacename > Session</interfacename>
instances.</para>
2009-06-26 11:37:18 +08:00
<para > The <interfacename > DataSource</interfacename> bean definition will
2009-07-31 02:29:56 +08:00
be similar to the local JDBC example shown previously and thus not shown
in the following example.</para>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<!-- TR: added the following clarification rather than embed it in the text above -->
<note >
<para > If the <interfacename > DataSource</interfacename> , used by any
non-JTA transaction manager, is looked up via JNDI and managed by a Java
EE container then it should be non-transactional because the Spring
Framework, rather than the Java EE container, will manage the
transactions.</para>
</note>
<para > The <literal > txManager</literal> bean in this case is of the
2009-06-26 11:37:18 +08:00
<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>
<programlisting language= "xml" > < bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
< 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>
2009-07-31 02:29:56 +08:00
<para > If you are using Hibernate and Java EE container managed JTA
transactions, then you should simply use the same
<classname > JtaTransactionManager</classname> as in the previous JTA
example for JDBC.<!-- Use it to do what? Below, this *what* is identical to JTA config
TR: I clarified this a bit
--></para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < bean id="txManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> </programlisting>
2009-07-31 02:29:56 +08:00
<note >
<para > If you use JTA then your transacton manager definition will look
the same regardles of what data access technology you use, be it JDBC,
Hibernate JPA or any other supported technology. This is due to the fact
that JTA transactions are global transactions, which can enlist any
transactional resource.</para>
</note>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > In all these cases, application code does not need to change. You
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>
2009-03-19 04:00:49 +08:00
</section>
<section id= "tx-resource-synchronization" >
2009-07-31 02:29:56 +08:00
<title > Synchronizing resources with transactions</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > It should now be clear how you create different transaction
managers, and how they are linked to related resources that need to be
2009-06-26 11:37:18 +08:00
synchronized to transactions (for example
<classname > DataSourceTransactionManager</classname> to a JDBC
<interfacename > DataSource</interfacename> ,
2009-03-19 04:00:49 +08:00
<classname > HibernateTransactionManager</classname> to a Hibernate
2009-07-31 02:29:56 +08:00
<interfacename > SessionFactory</interfacename> , and so forth). This section
describes how the application code, directly or indirectly using a
persistence API such as JDBC, Hibernate, or JDO, ensures that these
resources are created, reused, and cleaned up properly. The section also
discusses how transaction synchronization is triggered (optionally)
through the relevant
<interfacename > PlatformTransactionManager</interfacename> .<!-- I broke into two sentences. Last part of sentence unclear,revise to say what triggers tx synch. Revise sentences if necessray. --> </para>
2009-03-19 04:00:49 +08:00
<section id= "tx-resource-synchronization-high" >
2009-07-31 02:29:56 +08:00
<title > High-level synchronization approach</title>
<para > The preferred approach is to use Spring's highest level template
based persistence integration APIs or to use native ORM APIs with
transaction aware factory beans or proxies for managing the native
resource factories. These transaction aware solutions internally handle
resource creation and reuse, cleanup, optional transaction
synchronization of the resources, and exception mapping. Thus user data
access code does not have to address these tasks, but can be focused
purely on non-boilerplate persistence logic. Generally, you use the
native ORM API or a <emphasis > template</emphasis> approach for JDBC
access using the <classname > JdbcTemplate</classname> . All of these
solutions are detailed in subsequent chapters of this reference
documentation.<!-- If this approach is preferred, why not give examples here as you do with less desirable approaches? At least provide --> <!-- x - refs? Also is it correct to refer to APIs, then give classes as examples? Should this be reworded?
TR: I re-wrote this to match the current preferred approaches--></para>
2009-03-19 04:00:49 +08:00
</section>
<section id= "tx-resource-synchronization-low" >
2009-07-31 02:29:56 +08:00
<title > Low-level synchronization approach</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > Classes such as <classname > DataSourceUtils</classname> (for JDBC),
<classname > EntityManagerFactoryUtils</classname> (for JPA),
2009-03-19 04:00:49 +08:00
<classname > SessionFactoryUtils</classname> (for Hibernate),
2009-06-26 11:37:18 +08:00
<classname > PersistenceManagerFactoryUtils</classname> (for JDO), and so
2009-07-31 02:29:56 +08:00
on exist at a lower level. When you want the application code to deal
directly with the resource types of the native persistence APIs, you use
these classes to ensure that proper Spring Framework-managed instances
are obtained, transactions are (optionally) synchronized, and exceptions
that occur in the process are properly mapped to a consistent
API.</para>
2009-06-26 11:37:18 +08:00
<para > For example, in the case of JDBC, instead of the traditional JDBC
approach of calling the <literal > getConnection()</literal> method on the
2009-07-31 02:29:56 +08:00
<interfacename > DataSource</interfacename> , you instead use Spring's
2009-03-19 04:00:49 +08:00
<classname > org.springframework.jdbc.datasource.DataSourceUtils</classname>
class as follows:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > Connection conn = DataSourceUtils.getConnection(dataSource);</programlisting>
2009-07-31 02:29:56 +08:00
<para > If an existing transaction already has a connection synchronized
(linked) to it, that instance is returned. Otherwise, the method call
triggers the creation of a new connection, which is (optionally)
synchronized to any existing transaction, and made available for
subsequent reuse in that same transaction. As mentioned, any
<exceptionname > SQLException</exceptionname> is wrapped in a Spring
2009-06-26 11:37:18 +08:00
Framework
2009-07-31 02:29:56 +08:00
<exceptionname > CannotGetJdbcConnectionException</exceptionname> , one of
2009-06-26 11:37:18 +08:00
the Spring Framework's hierarchy of unchecked DataAccessExceptions. This
2009-07-31 02:29:56 +08:00
approach gives you more information than can be obtained easily from the
2009-06-26 11:37:18 +08:00
<exceptionname > SQLException</exceptionname> , and ensures portability
2009-07-31 02:29:56 +08:00
across databases, even across different persistence technologies.</para>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > This approach also works without Spring transaction management
(transaction synchronization is optional), so you can use it whether or
not you are using Spring for transaction management.</para>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > Of course, once you have used Spring's JDBC support, JPA support
or Hibernate support, you will generally prefer not to use
2009-06-26 11:37:18 +08:00
<classname > DataSourceUtils</classname> or the other helper classes,
2009-07-31 02:29:56 +08:00
because you will be much happier working through the Spring abstraction
than directly with the relevant APIs. For example, if you use the Spring
2009-03-19 04:00:49 +08:00
<classname > JdbcTemplate</classname> or <literal > jdbc.object</literal>
2009-06-26 11:37:18 +08:00
package to simplify your use of JDBC, correct connection retrieval
2009-07-31 02:29:56 +08:00
occurs behind the scenes and you won't need to write any special
2009-06-26 11:37:18 +08:00
code.</para>
2009-07-31 02:29:56 +08:00
<!-- I don't understand this. Why tell them to use DataSourceUtils and then say you will prefer Spring abstraction? Why not give example of using Spring abstraction? -->
2009-03-19 04:00:49 +08:00
</section>
<section id= "tx-resource-synchronization-tadsp" >
<title > <classname > TransactionAwareDataSourceProxy</classname> </title>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<para > At the very lowest level exists the
<classname > TransactionAwareDataSourceProxy</classname> class. This is a
2009-06-26 11:37:18 +08:00
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
2009-07-31 02:29:56 +08:00
provided by a Java EE server.<!-- What is the purpose of TransactionAwareDataSourceProxy, do you use it instead of 4.2 or 4.1 approaches or in addition to? --> </para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<para > It should almost never be necessary or desirable to use this
2009-07-31 02:29:56 +08:00
class, except when existing code must be called and passed a standard
JDBC <interfacename > DataSource</interfacename> interface implementation.
In that case, it is possible that this code is usable, but participating
in Spring managed transactions. It is preferable to write your new code
by using the higher level abstractions mentioned above.</para>
2009-03-19 04:00:49 +08:00
</section>
</section>
<section id= "transaction-declarative" >
<title > Declarative transaction management</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<note >
<para > Most Spring Framework users choose declarative transaction
management. This option has the least impact on application code, and
hence is most consistent with the ideals of a
<emphasis > non-invasive</emphasis> lightweight container.</para>
</note>
<para > Spring Framework's declarative transaction management is made
possible with Spring aspect-oriented programming (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 > Spring Framework's declarative transaction management is similar to
EJB CMT in that you can 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 between the two types of transaction
management are:</para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<itemizedlist >
<listitem >
2009-07-31 02:29:56 +08:00
<para > Unlike EJB CMT, which is tied to JTA, Spring Framework's
2009-06-26 11:37:18 +08:00
declarative transaction management works in any environment. It can
2009-07-31 02:29:56 +08:00
work with JTA transactions or local transactions using JDBC, JPA,
Hibernate or JDO by simple adjusting the configuration files.<!-- Indicate what kind of config changes? Changes to what TR: rewrote this to hoefully make it more clear --> </para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > You can apply Spring Framework declarative transaction
management to any class, not merely special classes such as
2009-06-26 11:37:18 +08:00
EJBs.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Spring Framework offers declarative <link
2009-06-26 11:37:18 +08:00
linkend="transaction-declarative-rolling-back"><emphasis > rollback
2009-07-31 02:29:56 +08:00
rules</emphasis> , </link> a feature with no EJB equivalent. Both
programmatic and declarative support for rollback rules is
2009-06-26 11:37:18 +08:00
provided.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Spring Framework enables you to customize transactional
behavior, by using AOP. For example, you can insert custom behavior in
the case of transaction rollback. You can also add arbitrary advice,
along with the transactional advice. With EJB CMT, cannot influence
the container's transaction management except with
2009-06-26 11:37:18 +08:00
<methodname > setRollbackOnly()</methodname> .</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Spring Framework does not support propagation of transaction
2009-06-26 11:37:18 +08:00
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>
2009-03-19 04:00:49 +08:00
</itemizedlist>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<sidebar >
2009-06-26 11:37:18 +08:00
<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
2009-03-19 04:00:49 +08:00
<classname > TransactionProxyFactoryBean</classname> beans.</para>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > The pre-Spring 2.0 configuration style is still 100% valid
2009-06-26 11:37:18 +08:00
configuration; think of the new <literal > < tx:tags/> </literal> as
simply defining <classname > TransactionProxyFactoryBean</classname> beans
2009-03-19 04:00:49 +08:00
on your behalf.</para>
</sidebar>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > The concept of rollback rules is important: they enable you to
specify which exceptions (and throwables) <!-- If no difference between exceptions and throwables, delete throwables. --> should
cause automatic rollback. You specify this declaratively, in
configuration, not in Java code. So, although you can still call
<methodname > setRollbackOnly()</methodname> on the
<interfacename > TransactionStatus</interfacename> object to roll back the
current transaction back, most often you can specify a rule that
<exceptionname > MyApplicationException</exceptionname> must always result
in rollback. The significant advantage to this option is that business
objects do not depend on the transaction infrastructure. For example, they
typically do not need to import Spring transaction APIs or other Spring
APIs.</para>
<para > Although EJB container default behavior automatically rolls 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 behavior.</para>
<!-- customize this so that what happens? -->
2009-03-19 04:00:49 +08:00
<section id= "tx-decl-explained" >
2009-07-31 02:29:56 +08:00
<title > Understanding Spring Framework's declarative transaction
2009-06-26 11:37:18 +08:00
implementation</title>
2009-07-31 02:29:56 +08:00
<para > It is not sufficient to tell you simply to annotate your classes
with the <interfacename > @Transactional</interfacename> annotation, add
the line (<literal > < tx:annotation-driven/> </literal> ) to your
2009-06-26 11:37:18 +08:00
configuration, and then expect you to understand how it all works. This
2009-07-31 02:29:56 +08:00
section explains the inner workings of Spring Framework's declarative
transaction infrastructure in the event of transaction-related
2009-06-26 11:37:18 +08:00
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>
2009-03-19 04:00:49 +08:00
<note >
2009-07-31 02:29:56 +08:00
<para > Spring AOP is covered in <xref linkend= "aop" /> .</para>
2009-03-19 04:00:49 +08:00
</note>
2009-06-26 11:37:18 +08:00
<para > Conceptually, calling a method on a transactional proxy looks like
this...</para>
2009-07-31 02:29:56 +08:00
<!-- I don't see this image in src file or in pdf. Maybe it was added to src after pdf was created? -->
2009-06-26 11:37:18 +08:00
<para > <mediaobject >
<imageobject role= "fo" >
<imagedata align= "center" fileref= "images/tx.png" format= "PNG" />
</imageobject>
<imageobject role= "html" >
<imagedata align= "center" fileref= "images/tx.png" format= "PNG" />
</imageobject>
</mediaobject> </para>
</section>
2009-03-19 04:00:49 +08:00
<section id= "transaction-declarative-first-example" >
2009-07-31 02:29:56 +08:00
<title > Example of declarative transaction implementation</title>
2009-06-26 11:37:18 +08:00
<para > Consider the following interface, and its attendant
2009-07-31 02:29:56 +08:00
implementation. This example uses the rote <classname > Foo</classname>
and <classname > Bar</classname> tropes so that you can concentrate on the
transaction usage without focusing on the domain model. 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 allows you to see
transactions created and then rolled back in response to the
<exceptionname > UnsupportedOperationException</exceptionname>
instance.</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > <lineannotation > // the service interface that we want to make transactional</lineannotation>
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);
2009-06-26 11:37:18 +08:00
}</programlisting>
<programlisting language= "java" > <lineannotation > // an implementation of the above interface</lineannotation>
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();
}
2009-06-26 11:37:18 +08:00
}</programlisting>
2009-07-31 02:29:56 +08:00
<para > Assume that the first two methods of the
<interfacename > FooService</interfacename> interface<literal > ,
getFoo(String)</literal> and <literal > getFoo(String, String),
</literal> must 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> must execute in the context of a
transaction with read-write semantics. The following configuration is
explained in detail in the next few paragraphs.</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > <lineannotation > < !-- from the file <literal > 'context.xml'</literal> --> </lineannotation>
< ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
2009-03-19 04:00:49 +08:00
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > xmlns:tx="http://www.springframework.org/schema/tx"</emphasis> </lineannotation>
2009-03-19 04:00:49 +08:00
xsi:schemaLocation="
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/beans
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd</emphasis> </lineannotation>
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/aop
2009-06-26 11:37:18 +08:00
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- this is the service object that we want to make transactional --> </lineannotation>
< bean id="fooService" class="x.y.service.DefaultFooService"/>
<lineannotation > < !-- the transactional advice (what 'happens'; see the <literal > < aop:advisor/> </literal> bean below) --> </lineannotation>
< tx:advice id="txAdvice" transaction-manager="txManager">
<lineannotation > < !-- the transactional semantics... --> </lineannotation>
< tx:attributes>
<lineannotation > < !-- all methods starting with <literal > 'get'</literal> are read-only --> </lineannotation>
< tx:method name="get*" read-only="true"/>
<lineannotation > < !-- other methods use the default transaction settings (see below) --> </lineannotation>
< tx:method name="*"/>
< /tx:attributes>
< /tx:advice>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- ensure that the above transactional advice runs for any execution
of an operation defined by the <interfacename > FooService</interfacename> interface --> </lineannotation>
< aop:config>
< aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
< aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
< /aop:config>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- don't forget the <interfacename > DataSource</interfacename> --> </lineannotation>
< 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>
< bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
< property name="dataSource" ref="dataSource"/>
< /bean>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- other <literal > < bean/> </literal> definitions here --> </lineannotation>
< /beans> </programlisting>
2009-03-19 04:00:49 +08:00
2009-07-31 02:29:56 +08:00
<para > Examine the preceding configuration. You want to make a service
object, the <literal > fooService</literal> bean, transactional. The
transaction semantics to apply are encapsulated in the
<literal > < tx:advice/> </literal> definition. The
<literal > < tx:advice/> </literal> definition reads as
2009-06-26 11:37:18 +08:00
<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
2009-07-31 02:29:56 +08:00
<literal > transaction-manager</literal> attribute of the
2009-06-26 11:37:18 +08:00
<literal > < tx:advice/> </literal> tag is set to the name of the
<interfacename > PlatformTransactionManager</interfacename> bean that is
2009-07-31 02:29:56 +08:00
going to <emphasis > drive</emphasis> the transactions, in this case, the
<literal > txManager</literal> bean.</para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<tip >
2009-07-31 02:29:56 +08:00
<para > You can omit the <literal > transaction-manager</literal>
attribute in the transactional advice
(<literal > < tx:advice/> </literal> ) if the bean name of the
2009-06-26 11:37:18 +08:00
<interfacename > PlatformTransactionManager</interfacename> that you
2009-07-31 02:29:56 +08:00
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 must use the
<literal > transaction-manager</literal> attribute explicitly, as in the
preceding example.</para>
2009-03-19 04:00:49 +08:00
</tip>
2009-06-26 11:37:18 +08:00
<para > The <literal > < aop:config/> </literal> definition ensures that
2009-07-31 02:29:56 +08:00
the transactional advice defined by the <literal > txAdvice</literal> bean
executes at the appropriate points in the program. First you define a
pointcut that matches the execution of any operation defined in the
<interfacename > FooService</interfacename> interface
(<literal > fooServiceOperation</literal> ). Then you associate the
pointcut with the <literal > txAdvice</literal> using an advisor. The
2009-06-26 11:37:18 +08:00
result indicates that at the execution of a
2009-07-31 02:29:56 +08:00
<literal > fooServiceOperation</literal> , the advice defined by
<literal > txAdvice</literal> will be run.</para>
2009-06-26 11:37:18 +08:00
<para > The expression defined within the
<literal > < aop:pointcut/> </literal> element is an AspectJ pointcut
2009-07-31 02:29:56 +08:00
expression; see <xref linkend= "aop" /> for more details on pointcut
expressions in Spring 2.0.</para>
2009-06-26 11:37:18 +08:00
<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>
<programlisting language= "xml" > < aop:config>
< aop:pointcut id="fooServiceMethods" expression="execution(* x.y.service.*.*(..))"/>
< aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceMethods"/>
2009-07-31 02:29:56 +08:00
< /aop:config> </programlisting>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > <note >
<para > <emphasis > In this example it is assumed that all your service
interfaces are defined in the <literal > x.y.service</literal>
package; see <xref linkend= "aop" /> for more
details.</emphasis> </para>
</note> </para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<para > Now that we've analyzed the configuration, you may be asking
2009-06-26 11:37:18 +08:00
yourself, <quote > <emphasis > Okay... but what does all this configuration
actually do?</emphasis> </quote> .</para>
2009-07-31 02:29:56 +08:00
<para > The above configuration will be used to create a transactional
proxy around the object that is created from the
<literal > fooService</literal> bean definition. <!-- Clarify what you mean by around the object; do you mean associated with the object? Revise to clarify. Around is vague. --> The
proxy will be configured with the transactional advice, so that when an
appropriate method is invoked <emphasis > on the proxy</emphasis> , a
transaction is started, suspended, marked as read-only, and so on,
depending on the transaction configuration associated with that method.
Consider the following program that test drives the above
configuration:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > 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());
}
2009-06-26 11:37:18 +08:00
}</programlisting>
2009-07-31 02:29:56 +08:00
<para > The output from running the preceding program will resemble the
following. (The Log4J output and the stack trace from the
UnsupportedOperationException thrown by the insertFoo(..) method of the
DefaultFooService class have been truncated for clarity.)</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > <lineannotation > <emphasis role= "bold" > < !-- the Spring container is starting up... --> </emphasis> </lineannotation>
2009-03-19 04:00:49 +08:00
[AspectJInvocationContextExposingAdvisorAutoProxyCreator] - Creating implicit proxy
for bean 'fooService' with 0 common interceptors and 1 specific interceptors
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > < !-- the <classname > DefaultFooService</classname> is actually proxied --> </emphasis> </lineannotation>
2009-03-19 04:00:49 +08:00
[JdkDynamicAopProxy] - Creating JDK dynamic proxy for [x.y.service.DefaultFooService]
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > < !-- ... the <literal > insertFoo(..)</literal> method is now being invoked on the proxy --> </emphasis> </lineannotation>
2009-03-19 04:00:49 +08:00
[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > < !-- the transactional advice kicks in here... --> </emphasis> </lineannotation>
2009-03-19 04:00:49 +08:00
[DataSourceTransactionManager] - Creating new transaction with name [x.y.service.FooService.insertFoo]
[DataSourceTransactionManager] - Acquired Connection
[org.apache.commons.dbcp.PoolableConnection@a53de4] for JDBC transaction
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > < !-- the <literal > insertFoo(..)</literal> method from <classname > DefaultFooService</classname> throws an exception... --> </emphasis> </lineannotation>
2009-03-19 04:00:49 +08:00
[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]
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > < !-- and the transaction is rolled back (by default, <exceptionname > RuntimeException</exceptionname> instances cause rollback) --> </emphasis> </lineannotation>
2009-03-19 04:00:49 +08:00
[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
2009-07-31 02:29:56 +08:00
at x.y.service.DefaultFooService.insertFoo(DefaultFooService.java:14)
2009-06-26 11:37:18 +08:00
<lineannotation > <emphasis role= "bold" > < !-- AOP infrastructure stack trace elements removed for clarity --> </emphasis> </lineannotation>
2009-07-31 02:29:56 +08:00
at $Proxy0.insertFoo(Unknown Source)
at Boot.main(Boot.java:11)</programlisting>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-declarative-rolling-back" >
2009-07-31 02:29:56 +08:00
<title > Rolling back a declarative transaction</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > The previous section outlined the basics of how to specify
transactional settings for classes, typically service layer classes,
declaratively in your application. This section describes how you can
control the rollback of transactions in a simple declarative
2009-06-26 11:37:18 +08:00
fashion.</para>
2009-07-31 02:29:56 +08:00
<para > The recommended way to indicate to 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. Spring Framework's
transaction infrastructure code, in its default configuration, will
catch any unhandled <exceptionname > Exception</exceptionname> as it
bubbles up the call stack, and mark the transaction for rollback.<!-- I changed to *can be configured* because next sentence says it does not do this by default in all cases.
TR: I changed it to *in its default configuration*--></para>
<para > However, Spring Framework's transaction infrastructure code, 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
2009-06-26 11:37:18 +08:00
<exceptionname > RuntimeException</exceptionname> .
2009-07-31 02:29:56 +08:00
(<exceptionname > Error</exceptionname> s will also - by default - result
in a rollback). Checked exceptions that are thrown from a transactional
method do <emphasis > not</emphasis> result in rollback.<!-- I revised preceding because it says ONLY first case is rolled back by default, but then says Errors are also marked by default.
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
TR: Errors aren't thrown by application code, only checked or unchecked exceptions are. So the Errors part is just clarifying that
if the underlying application server infrastructure throws an Error the transaction will be rolled back--></para>
<para > You can configure exactly which
<exceptionname > Exception</exceptionname> types mark a transaction for
rollback. The following XML snippet demonstrates how you configure
rollback for a checked, application-specific
<exceptionname > Exception</exceptionname> type.</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < tx:advice id="txAdvice" transaction-manager="txManager">
< tx:attributes>
< tx:method name="get*" read-only="true" <lineannotation > <emphasis
role="bold">rollback-for="NoProductInStockException"</emphasis> </lineannotation> />
< tx:method name="*"/>
< /tx:attributes>
< /tx:advice> </programlisting>
2009-07-31 02:29:56 +08:00
<para > You can also specify 'no rollback rules', if you do
<emphasis > not</emphasis> want a transaction rolled back when an
exception is thrown. The following example tells Spring Framework's
2009-06-26 11:37:18 +08:00
transaction infrastructure to commit the attendant transaction even in
the face of an unhandled
<exceptionname > InstrumentNotFoundException</exceptionname> .</para>
<programlisting language= "xml" > < tx:advice id="txAdvice">
< tx:attributes>
< tx:method name="updateStock" <lineannotation > <emphasis role= "bold" > no-rollback-for="InstrumentNotFoundException"</emphasis> </lineannotation> />
< tx:method name="*"/>
< /tx:attributes>
< /tx:advice> </programlisting>
2009-07-31 02:29:56 +08:00
<para > When Spring Framework's transaction infrastructure catches an
exception and is consults configured rollback rules to determine whether
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> results in a
rollback of the attendant transaction.</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < tx:advice id="txAdvice">
< tx:attributes>
< tx:method name="*" rollback-for="Throwable" no-rollback-for="InstrumentNotFoundException"/>
< /tx:attributes>
< /tx:advice> </programlisting>
2009-07-31 02:29:56 +08:00
<para > You can also indicate a required rollback
<emphasis > programmatically</emphasis> . Although very simple, this
process is quite invasive, and tightly couples your code to Spring
Framework's transaction infrastructure:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > public void resolvePosition() {
2009-03-19 04:00:49 +08:00
try {
2009-06-26 11:37:18 +08:00
<lineannotation > // some business logic...</lineannotation>
2009-03-19 04:00:49 +08:00
} catch (NoProductInStockException ex) {
2009-06-26 11:37:18 +08:00
<lineannotation > // trigger rollback programmatically</lineannotation>
2009-03-19 04:00:49 +08:00
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
2009-06-26 11:37:18 +08:00
}</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
2009-07-31 02:29:56 +08:00
clean POJO-based architecture.</para>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-declarative-diff-tx" >
2009-06-26 11:37:18 +08:00
<title > Configuring different transactional semantics for different
beans</title>
<para > Consider the scenario where you have a number of service layer
2009-07-31 02:29:56 +08:00
objects, and you want to apply a <emphasis > totally different</emphasis>
transactional configuration to each of them. You do this by defining
distinct <literal > < aop:advisor/> </literal> elements with differing
<literal > pointcut</literal> and <literal > advice-ref</literal> attribute
values.</para>
<para > As a point of comparison, first 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-06-26 11:37:18 +08:00
<programlisting language= "xml" > < ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
2009-03-19 04:00:49 +08:00
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="
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/beans
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/tx
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/aop
2009-06-26 11:37:18 +08:00
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:config>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:pointcut id="serviceOperation"
expression="<lineannotation > execution(* x.y.service..*Service.*(..))</lineannotation> "/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< /aop:config>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- these two beans will be transactional... --> </lineannotation>
< bean id="fooService" class="x.y.service.DefaultFooService"/>
< bean id="barService" class="x.y.service.extras.SimpleBarService"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- ... and these two beans won't --> </lineannotation>
< bean id="anotherService" class="org.xyz.SomeService"/> <lineannotation > < !-- (not in the right package) --> </lineannotation>
< bean id="barManager" class="x.y.service.SimpleBarManager"/> <lineannotation > < !-- (doesn't end in 'Service') --> </lineannotation>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< tx:advice id="txAdvice">
< tx:attributes>
< tx:method name="get*" read-only="true"/>
< tx:method name="*"/>
< /tx:attributes>
< /tx:advice>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- other transaction infrastructure beans such as a <interfacename > PlatformTransactionManager</interfacename> omitted... --> </lineannotation>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< /beans> </programlisting>
2009-03-19 04:00:49 +08:00
2009-07-31 02:29:56 +08:00
<para > The following example shows how to configure two distinct beans
with totally different transactional settings.</para>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
2009-03-19 04:00:49 +08:00
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="
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/beans
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/tx
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/aop
2009-06-26 11:37:18 +08:00
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:config>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:pointcut id="defaultServiceOperation"
expression="<lineannotation > execution(* x.y.service.*Service.*(..))</lineannotation> "/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:pointcut id="noTxServiceOperation"
expression="<lineannotation > execution(* x.y.service.ddl.DefaultDdlManager.*(..))</lineannotation> "/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< /aop:config>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- this bean will be transactional (see the <literal > 'defaultServiceOperation'</literal> pointcut) --> </lineannotation>
< bean id="fooService" class="x.y.service.DefaultFooService"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- this bean will also be transactional, but with totally different transactional settings --> </lineannotation>
< bean id="anotherFooService" class="x.y.service.ddl.DefaultDdlManager"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< tx:advice id="defaultTxAdvice">
< tx:attributes>
< tx:method name="get*" read-only="true"/>
< tx:method name="*"/>
< /tx:attributes>
< /tx:advice>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< tx:advice id="noTxAdvice">
< tx:attributes>
< tx:method name="*" propagation="NEVER"/>
< /tx:attributes>
< /tx:advice>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- other transaction infrastructure beans such as a <interfacename > PlatformTransactionManager</interfacename> omitted... --> </lineannotation>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< /beans> </programlisting>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-declarative-txadvice-settings" >
<title > <literal > < tx:advice/> </literal> settings</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > This section summarizes the various transactional settings that
2009-06-26 11:37:18 +08:00
can be specified using the <literal > < tx:advice/> </literal> tag.
The default <literal > < tx:advice/> </literal> settings are:</para>
<para > <itemizedlist >
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > <link linkend= "tx-propagation" > Propagation setting</link> is
<literal > REQUIRED.</literal> </para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Isolation level is <literal > DEFAULT.</literal> </para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Transaction is read/write.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Transaction timeout defaults to the default timeout of the
underlying transaction system, or none if timeouts are not
supported.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Any <exceptionname > RuntimeException</exceptionname> triggers
rollback, and any checked <exceptionname > Exception</exceptionname>
does not.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
</itemizedlist> </para>
2009-07-31 02:29:56 +08:00
<para > You can change these default settings; the various attributes of
2009-06-26 11:37:18 +08:00
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" >
2009-03-19 04:00:49 +08:00
<title > <literal > < tx:method/> </literal> settings</title>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<tgroup cols= "4" >
2009-07-31 02:29:56 +08:00
<colspec colnum= "1" colwidth= "1*" />
<colspec colnum= "2" colwidth= "0.4*" />
<colspec colnum= "3" colwidth= "0.6*" />
<colspec colnum= "4" colwidth= "2*" />
2009-03-19 04:00:49 +08:00
<thead >
<row >
<entry > Attribute</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Required?</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Default</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Description</entry>
</row>
</thead>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<tbody >
<row >
<entry > <literal > name</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Yes</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > <para > Method name(s) with which the transaction
2009-06-26 11:37:18 +08:00
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,
2009-07-31 02:29:56 +08:00
<literal > get*</literal> , <literal > handle*</literal> ,<literal >
on*Event</literal> , and so forth.</para> </entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > propagation</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > No</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > REQUIRED</entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Transaction propagation behavior.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > isolation</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > No</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > DEFAULT</entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Transaction isolation level.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > timeout</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > No</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > -1</entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Transaction timeout value (in seconds).</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > read-only</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > No</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > false</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Is this transaction read-only?</entry>
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > rollback-for</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > No</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > <para > <literal > Exception(s)</literal> that trigger
rollback; comma-delimited. For example,
<literal > com.foo.MyBusinessException,ServletException.</literal> </para> </entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > no-rollback-for</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > No</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > <para > <literal > Exception(s)</literal> that do
2009-06-26 11:37:18 +08:00
<emphasis > not</emphasis> trigger rollback; comma-delimited.
For example,
2009-07-31 02:29:56 +08:00
<literal > com.foo.MyBusinessException,ServletException.</literal> </para> </entry>
2009-03-19 04:00:49 +08:00
</row>
</tbody>
</tgroup>
2009-06-26 11:37:18 +08:00
</table> </para>
</section>
2009-03-19 04:00:49 +08:00
<section id= "transaction-declarative-annotations" >
<title > Using <interfacename > @Transactional</interfacename> </title>
2009-06-26 11:37:18 +08:00
<para > In addition to the XML-based declarative approach to transaction
2009-07-31 02:29:56 +08:00
configuration, you can use an annotation-based approach. Declaring
transaction semantics directly in the Java source code puts the
declarations much closer to the affected code. There is not much danger
of undue coupling, because code that is meant to be used transactionally
is almost always deployed that way anyway.</para>
2009-06-26 11:37:18 +08:00
<para > The ease-of-use afforded by the use of the
<interfacename > @Transactional</interfacename> annotation is best
2009-07-31 02:29:56 +08:00
illustrated with an example, which is explained in the text that
follows. Consider the following class definition:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > <lineannotation > // the service class that we want to make transactional</lineannotation>
<emphasis role= "bold" > @Transactional</emphasis>
2009-03-19 04:00:49 +08:00
public class DefaultFooService implements FooService {
Foo getFoo(String fooName);
Foo getFoo(String fooName, String barName);
void insertFoo(Foo foo);
void updateFoo(Foo foo);
2009-06-26 11:37:18 +08:00
}</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
2009-07-31 02:29:56 +08:00
<emphasis > one</emphasis> line of XML configuration:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > <lineannotation > < !-- from the file <literal > 'context.xml'</literal> --> </lineannotation>
< ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
2009-03-19 04:00:49 +08:00
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="
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/beans
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/tx
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/aop
2009-06-26 11:37:18 +08:00
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- this is the service object that we want to make transactional --> </lineannotation>
< bean id="fooService" class="x.y.service.DefaultFooService"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- enable the configuration of transactional behavior based on annotations --> </lineannotation>
<emphasis role= "bold" > < tx:annotation-driven transaction-manager="txManager"/> </emphasis>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- a <interfacename > PlatformTransactionManager</interfacename> is still required --> </lineannotation>
< bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<lineannotation > < !-- (this dependency is defined somewhere else) --> </lineannotation>
< property name="dataSource" ref="dataSource"/>
< /bean>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- other <literal > < bean/> </literal> definitions here --> </lineannotation>
< /beans> </programlisting>
2009-03-19 04:00:49 +08:00
<tip >
2009-07-31 02:29:56 +08:00
<para > You can 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 use the <literal > transaction-manager</literal> attribute
explicitly, as in the preceding example.</para>
2009-03-19 04:00:49 +08:00
</tip>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<sidebar >
2009-06-26 11:37:18 +08:00
<title > Method visibility and
<interfacename > @Transactional</interfacename> </title>
2009-07-31 02:29:56 +08:00
<para > When using proxies, you should apply the
<interfacename > @Transactional</interfacename> annotation only 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 is
raised, but the annotated method does not exhibit the configured
transactional settings. Consider the use of AspectJ (see below) if you
need to annotate non-public methods.</para>
2009-03-19 04:00:49 +08:00
</sidebar>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > You can place the <interfacename > @Transactional</interfacename>
annotation before an interface definition, a method on an interface, a
2009-06-26 11:37:18 +08:00
class definition, or a <emphasis > public</emphasis> method on a class.
2009-07-31 02:29:56 +08:00
However, the mere presence of the
2009-06-26 11:37:18 +08:00
<interfacename > @Transactional</interfacename> annotation is not enough
2009-07-31 02:29:56 +08:00
to activate the transactional behavior. The
<interfacename > @Transactional</interfacename> annotation is simply
metadata that can be consumed by something<!-- Please identify *something* . -->
that is <interfacename > @Transactional</interfacename> -aware and that can
use the metadata to configure the appropriate beans with transactional
behavior. In the preceding example, the
<literal > < tx:annotation-driven/> </literal> element
2009-03-19 04:00:49 +08:00
<emphasis > switches on</emphasis> the transactional behavior.</para>
2009-07-31 02:29:56 +08:00
<para > <tip >
<para > Spring recommends that you only annotate concrete classes (and
methods of 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 works only 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 are not recognized by the proxying and weaving
infrastructure, and the object will not be wrapped in a
transactional proxy, which would be decidedly
<emphasis > bad</emphasis> .</para>
</tip> </para>
<note >
<para > In proxy mode (which is the default), only external method calls
coming in through the proxy are intercepted. This means that
self-invocation, in effect, a method within the target object calling
another method of the target object, will not lead to an actual
transaction at runtime even if the invoked method is marked with
<interfacename > @Transactional</interfacename> .</para>
</note>
2009-03-19 04:00:49 +08:00
<para > Consider the use of AspectJ mode (see below) if you expect
2009-07-31 02:29:56 +08:00
self-invocations to be wrapped with transactions as well. <!-- *see below* is not clear re AspectJmode. Provide clear x - ref to mode in table below, or to Using Transactional with AspectJ section. Also clarify reference to *as well*. As well as what? --> <!-- Below, *in this case* meaning in *what* case? Explain what table shows. --> In
this case, there will not be a proxy in the first place; instead, the
target class will be weaved (that is, its byte code will be modified) in
order to turn <interfacename > @Transactional</interfacename> into runtime
behavior on any kind of method.</para>
2009-06-26 11:37:18 +08:00
<para > <table id= "tx-annotation-driven-settings" >
<title > <literal > < tx:annotation-driven/> </literal>
settings</title>
2009-03-19 04:00:49 +08:00
<tgroup cols= "3" >
<thead >
<row >
<entry > Attribute</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Default</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Description</entry>
</row>
</thead>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<tbody >
<row >
<entry > <literal > transaction-manager</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > transactionManager</entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > <para > Name of transaction manager to use. Only required
if the name of the transaction manager is not
2009-06-26 11:37:18 +08:00
<literal > transactionManager</literal> , as in the example
above.</para> </entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > mode</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > proxy</entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > <para > The default mode "proxy" processes annotated
2009-06-26 11:37:18 +08:00
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
2009-07-31 02:29:56 +08:00
"aspectj" instead weaves the affected classes with Spring's
AspectJ transaction aspect, modifying the target class byte
code to apply to any kind of method call. AspectJ weaving
requires spring-aspects.jar in the classpath as well as
load-time weaving (or compile-time weaving) enabled. (See
<xref linkend= "aop-aj-ltw-spring" /> for details on how to set
up load-time weaving.)</para> </entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > proxy-target-class</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > false</entry>
2009-06-26 11:37:18 +08:00
<entry > <para > Applies to proxy mode only. Controls what type of
transactional proxies are created for classes annotated with
the <interfacename > @Transactional</interfacename> annotation.
2009-07-31 02:29:56 +08:00
If the <literal > proxy-target-class</literal> attribute is set
to <literal > true</literal> , then class-based proxies are
created. If <literal > proxy-target-class</literal> is
<literal > false</literal> or if the attribute is omitted, then
standard JDK interface-based proxies are created. (See <xref
linkend="aop-proxying" /> for a detailed examination of the
different proxy types.)</para> </entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
<entry > <literal > order</literal> </entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Ordered.LOWEST_PRECEDENCE</entry>
2009-06-26 11:37:18 +08:00
<entry > <para > Defines the order of the transaction advice that
2009-07-31 02:29:56 +08:00
is applied to beans annotated with
<interfacename > @Transactional</interfacename> . (For more
information about the rules related to ordering of AOP advice,
see <xref linkend= "aop-ataspectj-advice-ordering" /> .) No
specified ordering means that the AOP subsystem determines the
order of the advice.</para> </entry>
2009-03-19 04:00:49 +08:00
</row>
</tbody>
</tgroup>
2009-06-26 11:37:18 +08:00
</table> </para>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<note >
2009-07-31 02:29:56 +08:00
<para > The <literal > proxy-target-class</literal> attribute on the
2009-06-26 11:37:18 +08:00
<literal > < tx:annotation-driven/> </literal> element controls what
type of transactional proxies are created for classes annotated with
the <interfacename > @Transactional</interfacename> annotation. If
2009-07-31 02:29:56 +08:00
<literal > proxy-target-class</literal> attribute is set to
<literal > true</literal> , class-based proxies are created. If
<literal > proxy-target-class</literal> is <literal > false</literal> or
if the attribute is omitted, standard JDK interface-based proxies are
created. (See <xref linkend= "aop-proxying" /> for a discussion of the
different proxy types.)</para>
2009-03-19 04:00:49 +08:00
</note>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<note >
2009-07-31 02:29:56 +08:00
<para > <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
2009-06-26 11:37:18 +08:00
<interfacename > WebApplicationContext</interfacename> for a
<classname > DispatcherServlet</classname> , it only checks for
<interfacename > @Transactional</interfacename> beans in your
2009-07-31 02:29:56 +08:00
controllers, and not your services. <!-- I don't understand the logic of preceding explanation. Also identify *it* in first sentence of Note. --> See
<xref linkend= "mvc-servlet" /> for more information.</para>
2009-03-19 04:00:49 +08:00
</note>
2009-06-26 11:37:18 +08:00
<para > The most derived location takes precedence when evaluating the
2009-07-31 02:29:56 +08:00
transactional settings for a method. <!-- Do you need to clarify what *most derived* location means? Lowest level? --> 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
2009-06-26 11:37:18 +08:00
<methodname > updateFoo(Foo)</methodname> method in the same class takes
precedence over the transactional settings defined at the class
level.</para>
<programlisting language= "java" > @Transactional(readOnly = true)
2009-03-19 04:00:49 +08:00
public class DefaultFooService implements FooService {
public Foo getFoo(String fooName) {
2009-06-26 11:37:18 +08:00
<lineannotation > // do something</lineannotation>
2009-03-19 04:00:49 +08:00
}
2009-06-26 11:37:18 +08:00
<lineannotation > // <emphasis role= "bold" > these</emphasis> settings have precedence for this method</lineannotation>
2009-03-19 04:00:49 +08:00
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void updateFoo(Foo foo) {
2009-06-26 11:37:18 +08:00
<lineannotation > // do something</lineannotation>
2009-03-19 04:00:49 +08:00
}
2009-06-26 11:37:18 +08:00
}</programlisting>
2009-03-19 04:00:49 +08:00
<section id= "transaction-declarative-attransactional-settings" >
<title > <interfacename > @Transactional</interfacename> settings</title>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<para > The <interfacename > @Transactional</interfacename> annotation is
metadata that specifies that an interface, class, or method must have
2009-06-26 11:37:18 +08:00
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
2009-07-31 02:29:56 +08:00
<interfacename > @Transactional</interfacename> settings are as
follows:</para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<itemizedlist >
<listitem >
2009-07-31 02:29:56 +08:00
<para > Propagation setting is
<literal > PROPAGATION_REQUIRED.</literal> </para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Isolation level is
<literal > ISOLATION_DEFAULT.</literal> </para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Transaction is read/write.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Transaction timeout defaults to the default timeout of the
underlying transaction system, or to none if timeouts are not
supported.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Any <exceptionname > RuntimeException</exceptionname> triggers
rollback, and any checked <exceptionname > Exception</exceptionname>
does not.<!-- Bullet list above does not exactly map to properties in table.ok? --> </para>
2009-03-19 04:00:49 +08:00
</listitem>
</itemizedlist>
2009-06-26 11:37:18 +08:00
<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>
2009-03-19 04:00:49 +08:00
<tgroup cols= "3" >
<thead >
<row >
<entry > Property</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Type</entry>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<entry > Description</entry>
</row>
</thead>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<tbody >
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > <link
linkend="tx-propagation">propagation</link> </literal> </entry>
2009-03-19 04:00:49 +08:00
<entry > enum: <classname > Propagation</classname> </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Optional propagation setting.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > isolation</literal> </entry>
2009-03-19 04:00:49 +08:00
<entry > enum: <classname > Isolation</classname> </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Optional isolation level.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > readOnly</literal> </entry>
2009-03-19 04:00:49 +08:00
<entry > boolean</entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Read/write vs. read-only transaction</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > timeout</literal> </entry>
2009-03-19 04:00:49 +08:00
<entry > int (in seconds granularity)</entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Transaction timeout.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > rollbackFor</literal> </entry>
2009-07-31 02:29:56 +08:00
<entry > Array of <classname > Class</classname> objects, which
must be derived from
<classname > Throwable.</classname> </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Optional array of exception classes that <emphasis
role="bold">must</emphasis> cause rollback.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > rollbackForClassname</literal> </entry>
2009-07-31 02:29:56 +08:00
<entry > Array of class names. Classes must be derived from
<classname > Throwable.</classname> </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Optional array of names of exception classes that
<emphasis role= "bold" > must</emphasis> cause
rollback.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > noRollbackFor</literal> </entry>
2009-07-31 02:29:56 +08:00
<entry > Array of <classname > Class</classname> objects, which
must be derived from
<classname > Throwable.</classname> </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Optional array of exception classes that <emphasis
2009-06-26 11:37:18 +08:00
role="bold">must not</emphasis> cause rollback.</entry>
2009-03-19 04:00:49 +08:00
</row>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<row >
2009-06-26 11:37:18 +08:00
<entry > <literal > noRollbackForClassname</literal> </entry>
2009-07-31 02:29:56 +08:00
<entry > Array of <classname > String</classname> class names,
which must be derived from
<classname > Throwable.</classname> </entry>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<entry > Optional array of names of exception classes that
2009-06-26 11:37:18 +08:00
<emphasis role= "bold" > must not</emphasis> cause
2009-07-31 02:29:56 +08:00
rollback.</entry>
2009-03-19 04:00:49 +08:00
</row>
</tbody>
</tgroup>
2009-06-26 11:37:18 +08:00
</table> </para>
2009-07-31 02:29:56 +08:00
<para > Currently you cannot 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 + "." + <!-- Meaning of symbols is unclear. --> method name of the
2009-06-26 11:37:18 +08:00
transactionally-advised class. For example, if the
<methodname > handlePayment(..)</methodname> method of the
<classname > BusinessService</classname> class started a transaction,
the name of the transaction would be:
<literal > com.foo.BusinessService.handlePayment</literal> .</para>
</section>
2009-03-19 04:00:49 +08:00
</section>
<section id= "tx-propagation" >
<title > Transaction propagation</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<!-- Changed heading to be more explicit. These are settings, right?
TR: changed it back; it's not just settings, the section discusses propagation in general as well as the settings-->
<para > This section describes some semantics of transaction propagation
in Spring. Please note that this section is not an introduction to
transaction propagation proper; rather it details some of the semantics
regarding transaction propagation in Spring.</para>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > In Spring-managed transactions, be aware of the difference between
<emphasis > physical</emphasis> and <emphasis > logical</emphasis>
transactions, and how the propagation setting applies to this
difference.</para>
2009-06-26 11:37:18 +08:00
<section id= "tx-propagation-required" >
<title > Required</title>
<para > <mediaobject >
<imageobject >
<imagedata align= "center" fileref= "images/tx_prop_required.png"
format="PNG" />
</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
2009-07-31 02:29:56 +08:00
method that to which the setting is applied. Each such logical
transaction scope can determine rollback-only status individually,
with an outer transaction scope being logically independent from the
inner transaction scope. Of course, in case of standard
<literal > PROPAGATION_REQUIRED</literal> behavior, all these scopes<!-- OK? Need to identify *they*. -->
will be mapped to the same physical transaction. So a rollback-only
marker set in the inner transaction scope does affect the outer
transaction's chance to actually commit (as you would expect it
to).<!-- Do you need to explain what an inner transaction scope as opposed to an outer transaction scope? --> </para>
<para > However, in the case where an inner transaction scope sets the
rollback-only marker, the outer transaction 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> is thrown at that
point. This is <emphasis > expected behavior</emphasis> so that the
2009-06-26 11:37:18 +08:00
caller of a transaction can never be misled to assume that a commit
2009-07-31 02:29:56 +08:00
was performed when it really was not. So if an inner transaction (of
which the outer caller is not aware) silently marks a transaction as
rollback-only, the outer caller still calls commit. The outer caller
needs to receive an <classname > UnexpectedRollbackException</classname>
to indicate clearly that a rollback was performed instead.</para>
2009-06-26 11:37:18 +08:00
</section>
<section id= "tx-propagation-requires_new" >
<title > RequiresNew</title>
<para > <mediaobject >
<imageobject >
<imagedata align= "center"
fileref="images/tx_prop_requires_new.png"
format="PNG" />
</imageobject>
<caption > <para > PROPAGATION_REQUIRES_NEW</para> </caption>
</mediaobject> </para>
2009-07-31 02:29:56 +08:00
<para > <literal > PROPAGATION_REQUIRES_NEW</literal> , in contrast to
<type > PROPAGATION_REQUIRED</type> , uses a
2009-06-26 11:37:18 +08:00
<emphasis > completely</emphasis> independent transaction for each
affected transaction scope. In that case, the underlying physical
2009-07-31 02:29:56 +08:00
transactions are different and hence can commit or roll back
2009-06-26 11:37:18 +08:00
independently, with an outer transaction not affected by an inner
transaction's rollback status.</para>
</section>
<section id= "tx-propagation-nested" >
<title > Nested</title>
2009-07-31 02:29:56 +08:00
<para > <literal > PROPAGATION_NESTED</literal> 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 setting is typically mapped onto JDBC savepoints, so will
only work with JDBC resource transactions. See Spring's
<classname > DataSourceTransactionManager</classname> .</para>
2009-06-26 11:37:18 +08:00
</section>
</section>
<section id= "transaction-declarative-applying-more-than-just-tx-advice" >
2009-07-31 02:29:56 +08:00
<title > Advising transactional operations<!-- Need better heading? Executing transactional advice? --> </title>
2009-03-19 04:00:49 +08:00
2009-07-31 02:29:56 +08:00
<para > Suppose you want to execute <emphasis > both</emphasis>
transactional <emphasis > and</emphasis> some basic profiling advice. How
do you effect this in the context of
2009-06-26 11:37:18 +08:00
<literal > < tx:annotation-driven/> </literal> ?</para>
2009-07-31 02:29:56 +08:00
<para > When you invoke the <methodname > updateFoo(Foo)</methodname>
method, you want to see the following actions:<!-- I changed this to a numbered list because language indicated that one thing happens after another. --> </para>
2009-03-19 04:00:49 +08:00
2009-07-31 02:29:56 +08:00
<orderedlist >
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Configured profiling aspect starts up.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Transactional advice executes.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Method on the advised object executes.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Transaction commits.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-07-31 02:29:56 +08:00
<para > Profiling aspect reports exact duration of the whole
transactional method invocation.</para>
2009-03-19 04:00:49 +08:00
</listitem>
2009-07-31 02:29:56 +08:00
</orderedlist>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<note >
2009-06-26 11:37:18 +08:00
<para > This chapter is not concerned with explaining AOP in any great
2009-07-31 02:29:56 +08:00
detail (except as it applies to transactions). See <xref
linkend="aop" /> for detailed coverage of the following AOP
configuration and AOP in general.</para>
2009-03-19 04:00:49 +08:00
</note>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > Here is the code for a simple profiling aspect discussed above.
<!-- If you mean this code produces actions above, say that. TR: added 'discussed above' --> The
ordering of advice is controlled through the
<interfacename > Ordered</interfacename> interface. For full details on
advice ordering, see <xref
2009-06-26 11:37:18 +08:00
linkend="aop-ataspectj-advice-ordering" />.</para>
<programlisting language= "java" > 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;
2009-06-26 11:37:18 +08:00
<lineannotation > // allows us to control the ordering of advice</lineannotation>
2009-03-19 04:00:49 +08:00
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
2009-06-26 11:37:18 +08:00
<lineannotation > // this method <emphasis > is</emphasis> the around advice</lineannotation>
2009-03-19 04:00:49 +08:00
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;
}
}
2009-06-26 11:37:18 +08:00
</programlisting>
<programlisting language= "xml" > < ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
2009-03-19 04:00:49 +08:00
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="
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/beans
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/tx
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/aop
2009-06-26 11:37:18 +08:00
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
< bean id="fooService" class="x.y.service.DefaultFooService"/>
<lineannotation > < !-- this is the aspect --> </lineannotation>
< bean id="profiler" class="x.y.SimpleProfiler">
<lineannotation > < !-- execute before the transactional advice (hence the lower order number) --> </lineannotation>
< property name="order" <emphasis role= "bold" > value="1"</emphasis> />
< /bean>
< tx:annotation-driven transaction-manager="txManager" <emphasis
role="bold">order="200"</emphasis> />
< aop:config>
<lineannotation > < !-- this advice will execute <emphasis role= "bold" > around</emphasis> the transactional advice --> </lineannotation>
< 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>
2009-07-31 02:29:56 +08:00
<para > The result of the above configuration is a
<literal > fooService</literal> bean that has profiling and transactional
aspects applied to it <emphasis > in the desired order</emphasis> . <!-- By *that order,* indicate whether you mean the numbered process or the above example? Or are they the same?
TR: changed to 'desired'; seems clear that the desired order is profiling first followed by transactional aspect-->You
configure any number of additional aspects in similar fashion.</para>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > The following example effects the same setup as above, but uses
the purely XML declarative approach.</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < ?xml version="1.0" encoding="UTF-8"?>
< beans xmlns="http://www.springframework.org/schema/beans"
2009-03-19 04:00:49 +08:00
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="
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/beans
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/tx
2009-06-10 07:39:37 +08:00
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
2009-05-16 04:15:18 +08:00
http://www.springframework.org/schema/aop
2009-06-26 11:37:18 +08:00
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< bean id="fooService" class="x.y.service.DefaultFooService"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- the profiling advice --> </lineannotation>
< bean id="profiler" class="x.y.SimpleProfiler">
<lineannotation > < !-- execute before the transactional advice (hence the lower order number) --> </lineannotation>
<emphasis role= "bold" > < property name="order" value="1</emphasis> "/>
< /bean>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:config>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
< aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<lineannotation > < !-- will execute after the profiling advice (c.f. the order attribute) --> </lineannotation>
< aop:advisor
2009-03-19 04:00:49 +08:00
advice-ref="txAdvice"
pointcut-ref="entryPointMethod"
2009-06-26 11:37:18 +08:00
<emphasis role= "bold" > order="2</emphasis> "/> <lineannotation > < !-- order value is higher than the profiling aspect --> </lineannotation>
< 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>
< /beans> </programlisting>
<para > The result of the above configuration will be a
2009-07-31 02:29:56 +08:00
<literal > fooService</literal> bean that has profiling and transactional
aspects applied to it <emphasis > in that order</emphasis> . If you want
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 you simply swap the value of
the profiling aspect bean's <literal > order</literal> property so that it
is higher than the transactional advice's order value.<!-- Do you mean ...transactional advice *bean's* order value? --> </para>
<para > You configure additional aspects in similar fashion.</para>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-declarative-aspectj" >
2009-06-26 11:37:18 +08:00
<title > Using <interfacename > @Transactional</interfacename> with
AspectJ</title>
2009-03-19 04:00:49 +08:00
<para > It is also possible to use the Spring Framework's
2009-06-26 11:37:18 +08:00
<interfacename > @Transactional</interfacename> support outside of a
2009-07-31 02:29:56 +08:00
Spring container by means of an AspectJ aspect. To do so, you first
annotate your classes (and optionally your classes' methods) with the
<interfacename > @Transactional</interfacename> annotation, and then you
link (weave) your application with the
2009-03-19 04:00:49 +08:00
<classname > org.springframework.transaction.aspectj.AnnotationTransactionAspect</classname>
2009-06-26 11:37:18 +08:00
defined in the <filename
class="libraryfile">spring-aspects.jar</filename> file. The aspect must
2009-07-31 02:29:56 +08:00
also be configured with a transaction manager. You can 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" />. Because we're focusing
here on applications running outside of a Spring container, we'll show
you how to do it programmatically.</para>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<note >
2009-07-31 02:29:56 +08:00
<para > Prior to continuing, you may want to read <xref
2009-06-26 11:37:18 +08:00
linkend="transaction-declarative-annotations" /> and <xref
linkend="aop" /> respectively.</para>
2009-03-19 04:00:49 +08:00
</note>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > <lineannotation > // construct an appropriate transaction manager </lineannotation>
2009-03-19 04:00:49 +08:00
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource());
2009-06-26 11:37:18 +08:00
<lineannotation > // configure the <classname > AnnotationTransactionAspect</classname> to use it; this must be done before executing any transactional methods</lineannotation>
AnnotationTransactionAspect.aspectOf().setTransactionManager(txManager); </programlisting>
2009-03-19 04:00:49 +08:00
<note >
2009-06-26 11:37:18 +08:00
<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
2009-07-31 02:29:56 +08:00
Development Guide</ulink> ) or use load-time weaving. See <xref
linkend="aop-aj-ltw" /> for a discussion of load-time weaving with
AspectJ.</para>
2009-03-19 04:00:49 +08:00
</section>
</section>
<section id= "transaction-programmatic" >
<title > Programmatic transaction management</title>
2009-06-26 11:37:18 +08:00
<para > The Spring Framework provides two means of programmatic transaction
management:</para>
2009-03-19 04:00:49 +08:00
<itemizedlist >
<listitem >
<para > Using the <classname > TransactionTemplate</classname> .</para>
</listitem>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<listitem >
2009-06-26 11:37:18 +08:00
<para > Using a
<interfacename > PlatformTransactionManager</interfacename>
2009-03-19 04:00:49 +08:00
implementation directly.</para>
</listitem>
</itemizedlist>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > The Spring team generally recommends the
<classname > TransactionTemplate</classname> for programmatic transaction
management. The second approach is similar to using the JTA
<interfacename > UserTransaction</interfacename> API, although exception
handling is less cumbersome.</para>
2009-03-19 04:00:49 +08:00
<section id= "tx-prog-template" >
<title > Using the <classname > TransactionTemplate</classname> </title>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<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
2009-06-26 11:37:18 +08:00
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 >
2009-07-31 02:29:56 +08:00
<para > As you will see in the examples that follow, using the
<classname > TransactionTemplate</classname> absolutely couples you to
Spring's transaction infrastructure and APIs. Whether or not
2009-06-26 11:37:18 +08:00
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,
2009-07-31 02:29:56 +08:00
looks like the following. You, as an application developer, write a
2009-06-26 11:37:18 +08:00
<interfacename > TransactionCallback</interfacename> implementation
2009-07-31 02:29:56 +08:00
(typically expressed as an anonymous inner class) that contains the code
that you need to execute in the context of a transaction. You then pass
an instance of your custom
2009-06-26 11:37:18 +08:00
<interfacename > TransactionCallback</interfacename> to the
<methodname > execute(..)</methodname> method exposed on the
<classname > TransactionTemplate</classname> .</para>
<programlisting language= "java" > public class SimpleService implements Service {
<lineannotation > // single <classname > TransactionTemplate</classname> shared amongst all methods in this instance</lineannotation>
2009-03-19 04:00:49 +08:00
private final TransactionTemplate transactionTemplate;
2009-06-26 11:37:18 +08:00
<lineannotation > // use constructor-injection to supply the <interfacename > PlatformTransactionManager</interfacename> </lineannotation>
2009-03-19 04:00:49 +08:00
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() {
2009-06-26 11:37:18 +08:00
<lineannotation > // the code in this method executes in a transactional context</lineannotation>
2009-03-19 04:00:49 +08:00
public Object doInTransaction(TransactionStatus status) {
updateOperation1();
return resultOfUpdateOperation2();
}
});
}
2009-06-26 11:37:18 +08:00
}</programlisting>
2009-03-19 04:00:49 +08:00
<para > If there is no return value, use the convenient
2009-07-31 02:29:56 +08:00
<classname > TransactionCallbackWithoutResult</classname> class with an
anonymous class as follows:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > transactionTemplate.execute(new <emphasis
role="bold">TransactionCallbackWithoutResult</emphasis> () {
2009-03-19 04:00:49 +08:00
protected void doInTransactionWithoutResult(TransactionStatus status) {
updateOperation1();
updateOperation2();
}
2009-06-26 11:37:18 +08:00
});</programlisting>
2009-03-19 04:00:49 +08:00
<para > Code within the callback can roll the transaction back by calling
the <literal > setRollbackOnly()</literal> method on the supplied
2009-07-31 02:29:56 +08:00
<interfacename > TransactionStatus</interfacename> object:</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > transactionTemplate.execute(new TransactionCallbackWithoutResult() {
2009-03-19 04:00:49 +08:00
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
updateOperation1();
updateOperation2();
} catch (SomeBusinessExeption ex) {
2009-06-26 11:37:18 +08:00
<emphasis role= "bold" > status.setRollbackOnly();</emphasis>
2009-03-19 04:00:49 +08:00
}
}
2009-06-26 11:37:18 +08:00
});</programlisting>
<section id= "tx-prog-template-settings" >
<title > Specifying transaction settings</title>
2009-07-31 02:29:56 +08:00
<para > You can specify transaction settings such as the propagation
mode, the isolation level, the timeout, and so forth on the
2009-06-26 11:37:18 +08:00
<classname > TransactionTemplate</classname> either programmatically or
in configuration. <classname > TransactionTemplate</classname> instances
by default have the <link
linkend="transaction-declarative-txadvice-settings">default
2009-07-31 02:29:56 +08:00
transactional settings</link> . The following example shows the
programmatic customization of the transactional settings for a
specific <classname > TransactionTemplate:</classname> </para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > 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);
2009-06-26 11:37:18 +08:00
<lineannotation > // the transaction settings can be set here explicitly if so desired</lineannotation>
2009-03-19 04:00:49 +08:00
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED);
2009-06-26 11:37:18 +08:00
this.transactionTemplate.setTimeout(30); <lineannotation > // 30 seconds</lineannotation>
<lineannotation > // and so forth...</lineannotation>
2009-03-19 04:00:49 +08:00
}
2009-06-26 11:37:18 +08:00
}</programlisting>
2009-07-31 02:29:56 +08:00
<para > The following example defines a
2009-06-26 11:37:18 +08:00
<classname > TransactionTemplate</classname> with some custom
transactional settings, using Spring XML configuration. The
2009-07-31 02:29:56 +08:00
<literal > sharedTransactionTemplate</literal> can then be injected into
as many services as are required.</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "xml" > < bean id="sharedTransactionTemplate"
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
2009-07-31 02:29:56 +08:00
number of classes may share a single instance of a
<classname > TransactionTemplate</classname> , if a class needs to use a
2009-06-26 11:37:18 +08:00
<classname > TransactionTemplate</classname> with different settings (for
2009-07-31 02:29:56 +08:00
example, a different isolation level), then you need to create two
distinct <classname > TransactionTemplate</classname> instances.</para>
2009-06-26 11:37:18 +08:00
</section>
2009-03-19 04:00:49 +08:00
<section id= "transaction-programmatic-ptm" >
2009-06-26 11:37:18 +08:00
<title > Using the
<interfacename > PlatformTransactionManager</interfacename> </title>
2009-03-19 04:00:49 +08:00
<para > You can also use the
<interfacename > org.springframework.transaction.PlatformTransactionManager</interfacename>
directly to manage your transaction. Simply pass the implementation of
2009-07-31 02:29:56 +08:00
the <interfacename > PlatformTransactionManager</interfacename> you are
using to your bean through a bean reference. Then, using the
2009-03-19 04:00:49 +08:00
<interfacename > TransactionDefinition</interfacename> and
<interfacename > TransactionStatus</interfacename> objects you can
2009-07-31 02:29:56 +08:00
initiate transactions, roll back, and commit.</para>
2009-06-26 11:37:18 +08:00
<programlisting language= "java" > DefaultTransactionDefinition def = new DefaultTransactionDefinition();
<lineannotation > // explicitly setting the transaction name is something that can only be done programmatically</lineannotation>
2009-03-19 04:00:49 +08:00
def.setName("SomeTxName");
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = txManager.getTransaction(def);
try {
2009-06-26 11:37:18 +08:00
<lineannotation > // execute your business logic here</lineannotation>
2009-03-19 04:00:49 +08:00
}
catch (MyException ex) {
txManager.rollback(status);
throw ex;
}
2009-06-26 11:37:18 +08:00
txManager.commit(status);</programlisting>
2009-03-19 04:00:49 +08:00
</section>
</section>
<section id= "tx-decl-vs-prog" >
2009-06-26 11:37:18 +08:00
<title > Choosing between programmatic and declarative transaction
management</title>
2009-03-19 04:00:49 +08:00
<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
2009-06-26 11:37:18 +08:00
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>
2009-03-19 04:00:49 +08:00
<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
2009-06-26 11:37:18 +08:00
configuration cost of declarative transaction management is greatly
reduced.</para>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-application-server-integration" >
<title > Application server-specific integration</title>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<para > Spring's transaction abstraction generally is application server
2009-06-26 11:37:18 +08:00
agnostic. Additionally, Spring's
<classname > JtaTransactionManager</classname> class, which can optionally
perform a JNDI lookup for the JTA
2009-03-19 04:00:49 +08:00
<interfacename > UserTransaction</interfacename> and
2009-06-26 11:37:18 +08:00
<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
2009-07-31 02:29:56 +08:00
suspension. See the <classname > JtaTransactionManager</classname> Javadocs
for details.</para>
2009-06-26 11:37:18 +08:00
<para > Spring's <classname > JtaTransactionManager</classname> is the
2009-07-31 02:29:56 +08:00
standard choice to run on Java EE application servers, and is known to
work on all common servers. Advanced functionality such as transaction
suspension works 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, BEA WebLogic
Server, and Oracle OC4J. These adapters iare discussed in the following
sections.</para>
<para > <emphasis > For standard scenarios, including WebLogic Server,
WebSphere and OC4J, consider using the convenient
<literal > < tx:jta-transaction-manager/> </literal> configuration
element.</emphasis> When configured, this element automatically detects
the underlying server and chooses 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; rather, they are chosen automatically, with the standard
2009-06-26 11:37:18 +08:00
<classname > JtaTransactionManager</classname> as default fallback.</para>
2009-03-19 04:00:49 +08:00
<section id= "transaction-application-server-integration-websphere" >
<title > IBM WebSphere</title>
2009-06-26 11:37:18 +08:00
<para > On WebSphere 6.1.0.9 and above, the recommended Spring JTA
transaction manager to use is
<classname > WebSphereUowTransactionManager</classname> . This special
2009-07-31 02:29:56 +08:00
adapter leverages IBM's <interfacename > UOWManager</interfacename> API,
which is available in WebSphere Application Server 6.0.2.19 and later
and 6.1.0.9 and later. With this adapter, Spring-driven transaction
2009-06-26 11:37:18 +08:00
suspension (suspend/resume as initiated by
<literal > PROPAGATION_REQUIRES_NEW</literal> ) is officially supported by
IBM!</para>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-application-server-integration-weblogic" >
2009-07-31 02:29:56 +08:00
<title > BEA WebLogic Server</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > On WebLogic Server 9.0 or above, you typically would use the
2009-06-26 11:37:18 +08:00
<classname > WebLogicJtaTransactionManager</classname> instead of the
stock <classname > JtaTransactionManager</classname> class. This special
WebLogic-specific subclass of the normal
2009-03-19 04:00:49 +08:00
<classname > JtaTransactionManager</classname> supports the full power of
2009-06-26 11:37:18 +08:00
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>
2009-03-19 04:00:49 +08:00
</section>
<section id= "transaction-application-server-integration-oc4j" >
<title > Oracle OC4J</title>
2009-06-26 11:37:18 +08:00
2009-07-31 02:29:56 +08:00
<para > Spring ships a special adapter class for OC4J 10.1.3 or later
called <classname > OC4JJtaTransactionManager</classname> . This class 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 > 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>
2009-03-19 04:00:49 +08:00
</section>
</section>
<section id= "transaction-solutions-to-common-problems" >
<title > Solutions to common problems</title>
2009-06-26 11:37:18 +08:00
2009-03-19 04:00:49 +08:00
<section id= "transaction-solutions-to-common-problems-wrong-ptm" >
2009-06-26 11:37:18 +08:00
<title > Use of the wrong transaction manager for a specific
<interfacename > DataSource</interfacename> </title>
2009-07-31 02:29:56 +08:00
<para > Use the <emphasis > correct</emphasis>
2009-06-26 11:37:18 +08:00
<interfacename > PlatformTransactionManager</interfacename> implementation
2009-07-31 02:29:56 +08:00
based on your choice of transactional technologies and requirements.<!-- for *what* requirements? Identify *their* TR: clarified this a bit -->
Used properly, the Spring Framework merely provides a straightforward
and portable abstraction. If you are using global transactions, you
<emphasis > must</emphasis> use the
2009-06-26 11:37:18 +08:00
<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
2009-07-31 02:29:56 +08:00
operations. Otherwise the transaction infrastructure attempts to perform
local transactions on resources such as container
2009-06-26 11:37:18 +08:00
<interfacename > DataSource</interfacename> instances. Such local
2009-07-31 02:29:56 +08:00
transactions do not make sense, and a good application server treats
2009-06-26 11:37:18 +08:00
them as errors.</para>
2009-03-19 04:00:49 +08:00
</section>
</section>
<section id= "transaction-resources" >
2009-06-26 11:37:18 +08:00
<title > Further Resources</title>
2009-07-31 02:29:56 +08:00
<para > For more information about Spring Framework's transaction
support:</para>
2009-03-19 04:00:49 +08:00
2009-06-26 11:37:18 +08:00
<itemizedlist >
<listitem >
<para > <ulink
url="http://www.javaworld.com/javaworld/jw-01-2009/jw-01-spring-transactions.html">Distributed
transactions in Spring, with and without XA</ulink> is a JavaWorld
2009-07-31 02:29:56 +08:00
presentation in which SpringSource's David Syer guides you through
seven patterns for distributed transactions in Spring applications,
three of them with XA and four without.</para>
2009-06-26 11:37:18 +08:00
</listitem>
<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
2009-07-31 02:29:56 +08:00
examples of how to configure and use transactions with both the Spring
Framework and EJB3.</para>
2009-06-26 11:37:18 +08:00
</listitem>
</itemizedlist>
</section>
2009-03-19 04:00:49 +08:00
</chapter>