@vlad_mihalcea: A beginner's guide to JTA Transaction Type https://vladmihalcea.com/jta-transaction-type/…
Summary
Vlad Mihalcea explains how the JTA transaction type works, including the 2PC protocol and how to use JTA with Spring for global transactions across multiple data sources such as PostgreSQL and Ehcache.
View Cached Full Text
Cached at: 07/31/26, 10:53 AM
A beginner’s guide to JTA Transaction Type
https://t.co/woGAg3y312 https://t.co/vr3yfBZ7zT
JTA Transaction Type - Vlad Mihalcea
Source: https://vladmihalcea.com/jta-transaction-type/
Introduction
In this article, we are going to analyze how the JTA transaction type works.
Since this is the default transaction type when using Jakarta EE or Java EE applications, it’s very important to understand how JTA transactions work, especially since Spring Boot or Spring applications useRESOURCE_LOCALtransactions instead.
JTA Transaction Type
When using the JTA transaction type, you can operate modifications across multiple data sources in an atomic global transaction that either commits all changes or rolls them back.
To understand how JTA transactions work, consider the following diagram that depicts a global JTA transaction modifying both a PostgreSQL database and anEhcacheinstance:

JTA Transaction Type
- The application controls the transaction scope via the
UserTransactioninterface. - To participate in a global JTA transaction, a resource must implement the
XAResourceinterface, which provides theprepare,commit, androllbackmethods that will be called by the JTA transaction manager based on the2PC (Two-Phase Commit) protocol. Our application enlists theEhcacheXAResourceto coordinate the transaction outcome for the Ehcache-related changes and thePGXAConnectionto commit or roll back the changes that were done in the PostgreSQL database. - The application makes changes to the PostgreSQL database and to Ehcache and calls
commiton theUserTransaction. - The transaction manager will call
prepareon eachXAResourceso they can vote on the transaction outcome. This is the first phase of the 2PC protocol that allows the enlisted resources to achieve consensus. - If all resources agree to commit the transaction, the
commitmethod will be called on eachXAResource, and the changes operated by this JTA global transaction will become durable.
Using the JTA Transaction Type with Spring
The JPA specification defines two transaction types you could choose from: JTA and RESOURCE_LOCAL. By default, Jakarta EE and Java EE applications use the JTA transaction type, while Spring Boot uses the RESOURCE_LOCAL transaction type.
To use JTA in a Spring application, you would need a specific bean configuration.
First, you will have to create an instance of the JTAXADataSourceinterface. For PostgreSQL, we can use thePGXADataSource. Unlike the more common JDBCDataSource, theXADataSourcecan provide us with theXAResourcethat can be enlisted in a JTA global transaction.
However, since most data access frameworks operate with the JDBCDataSource, we will have to wrap thePGXADataSourceand return an instance of theDataSourceinterface, as illustrated by the following bean configuration:
@Bean
public DataSource dataSource() {
try {
PGXADataSource dataSource = new PGXADataSource();
dataSource.setUrl(jdbcUrl);
dataSource.setUser(jdbcUser);
dataSource.setPassword(jdbcPassword);
⠀
XARecoveryModule xaRecoveryModule = new XARecoveryModule();
GenericXADataSourceWrapper wrapper =
new GenericXADataSourceWrapper(xaRecoveryModule);
return wrapper.wrapDataSource(dataSource);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
We can then pass theDataSourceto the JPAEntityManagerFactoryvia the SpringLocalContainerEntityManagerFactoryBeanconfiguration:
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setJtaDataSource(dataSource());
emf.setPackagesToScan(packagesToScan());
⠀
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
emf.setJpaVendorAdapter(vendorAdapter);
emf.setJpaProperties(additionalProperties());
return emf;
}
Afterward, we will have to create an instance of theJtaTransactionManagerso that the Spring@Transactionalmethods can use JTA transactions.
However, the SpringJtaTransactionManageris not really a standalone JTA transaction manager, likeNarayanaorAtomikos. Instead, theJtaTransactionManageris simply an instance of theAbstractPlatformTransactionManagerthat can work with the SpringTransactionInterceptorAspect, which is responsible for managing the declarative@Transactionalmethods.
Therefore, when creating the SpringJtaTransactionManagerinstance, we need to provide an instance of the standalone JTA transaction manager that implements the Jakarta Transactions specification.
If you are using Narayana, the Spring bean configuration is going to look like this:
@Bean
public JtaTransactionManager transactionManager() {
JtaTransactionManager jtaTransactionManager = new JtaTransactionManager();
jtaTransactionManager.setTransactionManager(jtaTransactionManager());
jtaTransactionManager.setUserTransaction(jtaUserTransaction());
jtaTransactionManager.setAllowCustomIsolationLevels(true);
return jtaTransactionManager;
}
@Bean
public TransactionManagerImple jtaTransactionManager() {
TransactionManagerImple transactionManager = new TransactionManagerImple();
return transactionManager;
}
@Bean
public UserTransactionImple jtaUserTransaction() {
UserTransactionImple userTransactionManager = new UserTransactionImple();
return userTransactionManager;
}
If you enjoyed this article, I bet you are going to love myBookandVideo Coursesas well.
Conclusion
JTA transactions are needed if you have to operate changes on multiple data sources in an atomic fashion.
While theRESOURCE\_LOCALtransaction type can manage a single JDBCConnection, JTA allows you to span the transaction boundaries over multiple resources, such as database connections, JMS queues, or caches.
Similar Articles
Postgres transactions are a distributed systems superpower
This article explains how using Postgres transactions for workflow state co-located with application data eliminates idempotency and atomicity problems in distributed workflows, providing exactly-once execution.
Postgres by Example
A hands-on introduction to PostgreSQL using annotated SQL examples, covering basics to advanced topics.
Postgres data stored in Parquet on S3: LTAP architecture explained
Databricks introduces Lakebase LTAP architecture that stores Postgres data in Parquet on S3, enabling transactions and analytics on a single copy of data without CDC or mirroring.
How PgBouncer Works
A detailed technical guide explaining how PgBouncer works as a PostgreSQL connection pooler, covering its pooling modes, production deployment, and common pitfalls.
All you need is PostgreSQL
A detailed guide on using PostgreSQL as a single database to handle all aspects of a financial application, including schema design, state machines, triggers, and performance optimization.




