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:

Java
@Component
public class MyComponent {
    @TransactionalEventListener
    public void handleOrderCreatedEvent(CreationEvent<Order> creationEvent) {
        // ...
    }
}
Kotlin
@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.