Programmatic transaction management can usually only be a great idea if you have a small number of transactional
activities. For example, if you have a web application that only requires transactions for certain update
operations, you may not need to configure transaction proxies using Spring or any other technology. In this case,
the approach using TransactionTemplate
may be good. The ability to explicitly specify a transaction
name is only available when using a programmatic approach to transaction management.
On the other hand, if your application has a lot of transactional activities, declarative transaction management usually makes sense. It does not include transaction management in the business logic and is not difficult to configure. By using the Spring Framework rather than CMT from EJB, the cost of declarative transaction management configuration is significantly reduced.
Events within transaction boundaries
Starting with Spring 4.2, an event listener can be bound to a transaction phase. A typical example is handling an event when a transaction completes successfully. This allows you to use events more flexibly if the outcome of the current transaction is really important to the listener.
You can register a regular event listener using the @EventListener
annotation. If you need to bind it to
a transaction, use the @TransactionalEventListener
annotation. The default listener will then bind to
the commit phase of the transaction.
The following example demonstrates this concept. Let's assume that a component publishes an event that is generated in a specific order, and we need to define a listener that should only process that event after the transaction in which it was published has successfully committed. The following example sets up an event listener like this:
@Component
public class MyComponent {
@TransactionalEventListener
public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
// ...
}
}
@Component
class MyComponent {
@TransactionalEventListener
fun handleOrderCreatedEvent(creationEvent: CreationEvent<Order>) {
// ...
}
}
Annotation @TransactionalEventListener
exposes the phase
attribute, which allows you to
configure the transaction phase to which the listener should be bound. Valid phases are BEFORE_COMMIT
,
AFTER_COMMIT
(default), AFTER_ROLLBACK
, and AFTER_COMPLETION
, which combines
the completion of the transaction ( be it commit or rollback).
If the transaction fails, the listener is not called at all because we cannot maintain the required semantics.
However, you can override this logic by setting the fallbackExecution
attribute of the annotation to
true
.
The @TransactionalEventListener
annotation only works with thread-bound transactions managed by the
PlatformTransactionManager
. A reactive transaction managed by a
ReactiveTransactionManager
uses the Reactor context instead of thread-local attributes, so from the
point of view of the event listener there is no compatible active transaction in which it can participate.
Integration with application server
Spring's transaction abstraction is generally independent of the application server. Additionally, the JtaTransactionManager
class from Spring (which can optionally look up UserTransaction
and TransactionManager
objects from JTA via JNDI) automatically determines the location of the last object that depends on the application
server. Having access to TransactionManager
from JTA allows you to expand the semantics of transactions
- in particular, support the suspension of transactions. For details, see the javadoc at JtaTransactionManager
.
JtaTransactionManager
from Spring is the typical way to run on Java EE application servers and is known
to work on all common servers. Advanced functionality such as transaction suspension also works on many servers
(including GlassFish, JBoss, and Geronimo) without the need for special configuration. However, to fully support
transaction suspension and further advanced integration, Spring includes special adapters for WebLogic Server and
WebSphere. These adapters are described in the following sections.
For standard scenarios, including WebLogic Server and WebSphere, use the
<tx:jta-transaction-manager/>
configuration helper element. When configured, this element
automatically detects the primary server and selects the best transaction manager available for the platform. This
means that you do not have to explicitly configure server-specific adapter classes (as described in the following
sections). Rather, they are selected automatically, with the standard JtaTransactionManager
being the
default return option.
WebSphere from IBM
In WebSphere 6.1.0.9 and later, the recommended JTA transaction manager in Spring is WebSphereUowTransactionManager
.
This custom adapter uses the UOWManager
API from IBM, which is available in WebSphere Application
Server 6.1.0.9 and later. With this adapter, Spring-managed transaction suspension (suspense and resume initiated by
PROPAGATION_REQUIRES_NEW
) is officially supported by IBM.
WebLogic Server from Oracle
On WebLogic Server 9.0 or higher, it is common to use WebLogicJtaTransactionManager
instead of the
standard JtaTransactionManager
class. This special WebLogic-specific subclass of the regular JtaTransactionManager
supports all the functionality of Spring transaction definitions in a WebLogic-managed transaction environment, in
addition to the standard JTA semantics. Features include transaction names, isolation levels for each transaction,
and how to properly resume transactions in all cases.
Solving common problems
This section describes solutions to some common problems.
Using the wrong transaction manager for a specific DataSource
Use the correct PlatformTransactionManager
implementation based on your transaction technology choices
and requirements. When used correctly, the Spring Framework provides a simple and portable abstraction. If global
transactions are used, then you need to use the
org.springframework.transaction.jta.Jta.JtaTransactionManager
class (or its application server-specific
subclass) for all transactional operations. Otherwise, the transaction framework will attempt to perform
local transactions on resources such as containerized DataSource
instances. Such local transactions
have no meaning, and a properly functioning application server considers them errors.
Additional sources
For more information about transaction support in the Spring Framework, see:
-
Distributed transactions in Spring, with and without XAis a JavaWorld presentation in which Spring's David Sayer introduces you to seven patterns for distributed transactions in Spring applications, three with XA and four without.
-
Java Transaction Design Strategies is a book available in < a href="https://www.infoq.com/">InfoQ, which provides a well-grounded introduction to Java transactions. It also provides side-by-side examples of setting up and using transactions in both the Spring Framework and EJB3.