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