You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2391 lines
112 KiB
2391 lines
112 KiB
<?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">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">public interface TransactionStatus extends SavepointManager { |
|
|
|
boolean isNewTransaction(); |
|
|
|
boolean hasSavepoint(); |
|
|
|
void setRollbackOnly(); |
|
|
|
boolean isRollbackOnly(); |
|
|
|
void flush(); |
|
|
|
boolean isCompleted(); |
|
|
|
}</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"><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"><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"><?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-3.0.xsd |
|
http://www.springframework.org/schema/jee |
|
http://www.springframework.org/schema/jee/spring-jee-3.0.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> |
|
|
|
</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"><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"><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">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 align="center" fileref="images/tx.png" format="PNG" /> |
|
</imageobject> |
|
|
|
<imageobject role="html"> |
|
<imagedata align="center" fileref="images/tx.png" format="PNG" /> |
|
</imageobject> |
|
</mediaobject></para> |
|
</section> |
|
|
|
<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> |
|
|
|
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> |
|
|
|
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> |
|
<?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> |
|
xsi:schemaLocation=" |
|
http://www.springframework.org/schema/beans |
|
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd |
|
<lineannotation><emphasis role="bold">http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd</emphasis></lineannotation> |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<lineannotation><!-- this is the service object that we want to make transactional --></lineannotation> |
|
<bean id="fooService" class="x.y.service.DefaultFooService"/> |
|
|
|
<lineannotation><!-- the transactional advice (what 'happens'; see the <literal><aop:advisor/></literal> bean below) --></lineannotation> |
|
<tx:advice id="txAdvice" transaction-manager="txManager"> |
|
<lineannotation><!-- the transactional semantics... --></lineannotation> |
|
<tx:attributes> |
|
<lineannotation><!-- all methods starting with <literal>'get'</literal> are read-only --></lineannotation> |
|
<tx:method name="get*" read-only="true"/> |
|
<lineannotation><!-- other methods use the default transaction settings (see below) --></lineannotation> |
|
<tx:method name="*"/> |
|
</tx:attributes> |
|
</tx:advice> |
|
|
|
<lineannotation><!-- ensure that the above transactional advice runs for any execution |
|
of an operation defined by the <interfacename>FooService</interfacename> interface --></lineannotation> |
|
<aop:config> |
|
<aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/> |
|
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/> |
|
</aop:config> |
|
|
|
<lineannotation><!-- don't forget the <interfacename>DataSource</interfacename> --></lineannotation> |
|
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> |
|
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> |
|
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> |
|
<property name="username" value="scott"/> |
|
<property name="password" value="tiger"/> |
|
</bean> |
|
|
|
<lineannotation><!-- similarly, don't forget the <interfacename>PlatformTransactionManager</interfacename> --></lineannotation> |
|
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> |
|
<property name="dataSource" ref="dataSource"/> |
|
</bean> |
|
|
|
<lineannotation><!-- other <literal><bean/></literal> definitions here --></lineannotation> |
|
|
|
</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"><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">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> |
|
[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> |
|
[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> |
|
|
|
[TransactionInterceptor] - Getting transaction for x.y.service.FooService.insertFoo |
|
<lineannotation><emphasis role="bold"><!-- the transactional advice kicks in here... --></emphasis></lineannotation> |
|
[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> |
|
[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> |
|
[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> |
|
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"><tx:advice id="txAdvice" transaction-manager="txManager"> |
|
<tx:attributes> |
|
<tx:method name="get*" read-only="true" <lineannotation><emphasis |
|
role="bold">rollback-for="NoProductInStockException"</emphasis></lineannotation>/> |
|
<tx:method name="*"/> |
|
</tx:attributes> |
|
</tx:advice></programlisting> |
|
|
|
<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"><tx:advice id="txAdvice"> |
|
<tx:attributes> |
|
<tx:method name="updateStock" <lineannotation><emphasis role="bold">no-rollback-for="InstrumentNotFoundException"</emphasis></lineannotation>/> |
|
<tx:method name="*"/> |
|
</tx:attributes> |
|
</tx:advice></programlisting> |
|
|
|
<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"><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">public void resolvePosition() { |
|
try { |
|
<lineannotation>// some business logic...</lineannotation> |
|
} catch (NoProductInStockException ex) { |
|
<lineannotation>// trigger rollback programmatically</lineannotation> |
|
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"><?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-3.0.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<aop:config> |
|
|
|
<aop:pointcut id="serviceOperation" |
|
expression="<lineannotation>execution(* x.y.service..*Service.*(..))</lineannotation>"/> |
|
|
|
<aop:advisor pointcut-ref="serviceOperation" advice-ref="txAdvice"/> |
|
|
|
</aop:config> |
|
|
|
<lineannotation><!-- these two beans will be transactional... --></lineannotation> |
|
<bean id="fooService" class="x.y.service.DefaultFooService"/> |
|
<bean id="barService" class="x.y.service.extras.SimpleBarService"/> |
|
|
|
<lineannotation><!-- ... and these two beans won't --></lineannotation> |
|
<bean id="anotherService" class="org.xyz.SomeService"/> <lineannotation><!-- (not in the right package) --></lineannotation> |
|
<bean id="barManager" class="x.y.service.SimpleBarManager"/> <lineannotation><!-- (doesn't end in 'Service') --></lineannotation> |
|
|
|
<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> |
|
|
|
</beans></programlisting> |
|
|
|
<para>Find below an example of configuring two distinct beans with |
|
totally different transactional settings.</para> |
|
|
|
<programlisting language="xml"><?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-3.0.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<aop:config> |
|
|
|
<aop:pointcut id="defaultServiceOperation" |
|
expression="<lineannotation>execution(* x.y.service.*Service.*(..))</lineannotation>"/> |
|
|
|
<aop:pointcut id="noTxServiceOperation" |
|
expression="<lineannotation>execution(* x.y.service.ddl.DefaultDdlManager.*(..))</lineannotation>"/> |
|
|
|
<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> |
|
<bean id="fooService" class="x.y.service.DefaultFooService"/> |
|
|
|
<lineannotation><!-- this bean will also be transactional, but with totally different transactional settings --></lineannotation> |
|
<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> |
|
|
|
</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> |
|
<emphasis role="bold">@Transactional</emphasis> |
|
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> |
|
<?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-3.0.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<lineannotation><!-- this is the service object that we want to make transactional --></lineannotation> |
|
<bean id="fooService" class="x.y.service.DefaultFooService"/> |
|
|
|
<lineannotation><!-- enable the configuration of transactional behavior based on annotations --></lineannotation> |
|
<emphasis role="bold"><tx:annotation-driven transaction-manager="txManager"/></emphasis> |
|
|
|
<lineannotation><!-- a <interfacename>PlatformTransactionManager</interfacename> is still required --></lineannotation> |
|
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> |
|
<lineannotation><!-- (this dependency is defined somewhere else) --></lineannotation> |
|
<property name="dataSource" ref="dataSource"/> |
|
</bean> |
|
|
|
<lineannotation><!-- other <literal><bean/></literal> definitions here --></lineannotation> |
|
|
|
</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">@Transactional(readOnly = true) |
|
public class DefaultFooService implements FooService { |
|
|
|
public Foo getFoo(String fooName) { |
|
<lineannotation>// do something</lineannotation> |
|
} |
|
|
|
<lineannotation>// <emphasis role="bold">these</emphasis> settings have precedence for this method</lineannotation> |
|
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) |
|
public void updateFoo(Foo foo) { |
|
<lineannotation>// do something</lineannotation> |
|
} |
|
}</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 align="center" fileref="images/tx_prop_required.png" |
|
format="PNG" /> |
|
</imageobject> |
|
|
|
<caption><para>PROPAGATION_REQUIRED</para></caption> |
|
</mediaobject></para> |
|
|
|
<para>When the propagation setting is |
|
<literal>PROPAGATION_REQUIRED</literal>, a |
|
<emphasis>logical</emphasis> transaction scope is created for each |
|
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 align="center" |
|
fileref="images/tx_prop_requires_new.png" |
|
format="PNG" /> |
|
</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">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> |
|
public int getOrder() { |
|
return this.order; |
|
} |
|
|
|
public void setOrder(int order) { |
|
this.order = order; |
|
} |
|
|
|
<lineannotation>// this method <emphasis>is</emphasis> the around advice</lineannotation> |
|
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"><?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-3.0.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<bean id="fooService" class="x.y.service.DefaultFooService"/> |
|
|
|
<lineannotation><!-- this is the aspect --></lineannotation> |
|
<bean id="profiler" class="x.y.SimpleProfiler"> |
|
<lineannotation><!-- execute before the transactional advice (hence the lower order number) --></lineannotation> |
|
<property name="order" <emphasis role="bold">value="1"</emphasis>/> |
|
</bean> |
|
|
|
<tx:annotation-driven transaction-manager="txManager" <emphasis |
|
role="bold">order="200"</emphasis>/> |
|
|
|
<aop:config> |
|
<lineannotation><!-- this advice will execute <emphasis role="bold">around</emphasis> the transactional advice --></lineannotation> |
|
<aop:aspect id="profilingAspect" ref="profiler"> |
|
<aop:pointcut id="serviceMethodWithReturnValue" |
|
expression="execution(!void x.y..*Service.*(..))"/> |
|
<aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/> |
|
</aop:aspect> |
|
</aop:config> |
|
|
|
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> |
|
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/> |
|
<property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/> |
|
<property name="username" value="scott"/> |
|
<property name="password" value="tiger"/> |
|
</bean> |
|
|
|
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> |
|
<property name="dataSource" ref="dataSource"/> |
|
</bean> |
|
|
|
</beans></programlisting> |
|
|
|
<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"><?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-3.0.xsd |
|
http://www.springframework.org/schema/tx |
|
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd |
|
http://www.springframework.org/schema/aop |
|
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> |
|
|
|
<bean id="fooService" class="x.y.service.DefaultFooService"/> |
|
|
|
<lineannotation><!-- the profiling advice --></lineannotation> |
|
<bean id="profiler" class="x.y.SimpleProfiler"> |
|
<lineannotation><!-- execute before the transactional advice (hence the lower order number) --></lineannotation> |
|
<emphasis role="bold"><property name="order" value="1</emphasis>"/> |
|
</bean> |
|
|
|
<aop:config> |
|
|
|
<aop:pointcut id="entryPointMethod" expression="execution(* x.y..*Service.*(..))"/> |
|
|
|
<lineannotation><!-- will execute after the profiling advice (c.f. the order attribute) --></lineannotation> |
|
<aop:advisor |
|
advice-ref="txAdvice" |
|
pointcut-ref="entryPointMethod" |
|
<emphasis role="bold">order="2</emphasis>"/> <lineannotation><!-- order value is higher than the profiling aspect --></lineannotation> |
|
|
|
<aop:aspect id="profilingAspect" ref="profiler"> |
|
<aop:pointcut id="serviceMethodWithReturnValue" |
|
expression="execution(!void x.y..*Service.*(..))"/> |
|
<aop:around method="profile" pointcut-ref="serviceMethodWithReturnValue"/> |
|
</aop:aspect> |
|
|
|
</aop:config> |
|
|
|
<tx:advice id="txAdvice" transaction-manager="txManager"> |
|
<tx:attributes> |
|
<tx:method name="get*" read-only="true"/> |
|
<tx:method name="*"/> |
|
</tx:attributes> |
|
</tx:advice> |
|
|
|
<lineannotation><!-- other <bean/> definitions such as a <interfacename>DataSource</interfacename> and a <interfacename>PlatformTransactionManager</interfacename> here --></lineannotation> |
|
|
|
</beans></programlisting> |
|
|
|
<para>The result of the above configuration will be a |
|
<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> |
|
DataSourceTransactionManager txManager = new DataSourceTransactionManager(getDataSource()); |
|
|
|
<lineannotation>// configure the <classname>AnnotationTransactionAspect</classname> to use it; this must be done before executing any transactional methods</lineannotation> |
|
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">public class SimpleService implements Service { |
|
|
|
<lineannotation>// single <classname>TransactionTemplate</classname> shared amongst all methods in this instance</lineannotation> |
|
private final TransactionTemplate transactionTemplate; |
|
|
|
<lineannotation>// use constructor-injection to supply the <interfacename>PlatformTransactionManager</interfacename></lineannotation> |
|
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> |
|
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">transactionTemplate.execute(new <emphasis |
|
role="bold">TransactionCallbackWithoutResult</emphasis>() { |
|
|
|
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">transactionTemplate.execute(new TransactionCallbackWithoutResult() { |
|
|
|
protected void doInTransactionWithoutResult(TransactionStatus status) { |
|
try { |
|
updateOperation1(); |
|
updateOperation2(); |
|
} catch (SomeBusinessExeption ex) { |
|
<emphasis role="bold">status.setRollbackOnly();</emphasis> |
|
} |
|
} |
|
});</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">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> |
|
this.transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_UNCOMMITTED); |
|
this.transactionTemplate.setTimeout(30); <lineannotation>// 30 seconds</lineannotation> |
|
<lineannotation>// and so forth...</lineannotation> |
|
} |
|
}</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"><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">DefaultTransactionDefinition def = new DefaultTransactionDefinition(); |
|
<lineannotation>// explicitly setting the transaction name is something that can only be done programmatically</lineannotation> |
|
def.setName("SomeTxName"); |
|
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); |
|
|
|
TransactionStatus status = txManager.getTransaction(def); |
|
try { |
|
<lineannotation>// execute your business logic here</lineannotation> |
|
} |
|
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.1.0.9 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> |
|
</section> |
|
|
|
<section id="transaction-application-server-integration-weblogic"> |
|
<title>BEA WebLogic</title> |
|
|
|
<para>On WebLogic 9.0 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.javaworld.com/javaworld/jw-01-2009/jw-01-spring-transactions.html">Distributed |
|
transactions in Spring, with and without XA</ulink> is a JavaWorld |
|
feature where SpringSource's David Syer guides you through seven |
|
patterns for distributed transactions in Spring applications, three of |
|
them with XA and four without.</para> |
|
</listitem> |
|
|
|
<listitem> |
|
<para><ulink url="http://www.infoq.com/minibooks/JTDS">Java |
|
Transaction Design Strategies</ulink> is a book available from <ulink |
|
url="http://www.infoq.com/">InfoQ</ulink> that provides a well-paced |
|
introduction to transactions in Java. It also includes side-by-side |
|
examples of how to configure and use transactions using both the |
|
Spring Framework and EJB3.</para> |
|
</listitem> |
|
</itemizedlist> |
|
</section> |
|
</chapter>
|
|
|