RESOURCE_LOCAL JPA Transaction Type

Are you struggling with performance issues in your Spring, Jakarta EE, or Java EE application?

What if there were a tool that could automatically detect what caused performance issues in your JPA and Hibernate data access layer?

Wouldn’t it be awesome to have such a tool to watch your application and prevent performance issues during development, long before they affect production systems?

Well, Hypersistence Optimizer is that tool! And it works with Spring Boot, Spring Framework, Jakarta EE, Java EE, Quarkus, Micronaut, or Play Framework.

So, rather than fixing performance issues in your production system on a Saturday night, you are better off using Hypersistence Optimizer to help you prevent those issues so that you can spend your time on the things that you love!

Introduction

In this article, we are going to analyze how the RESOURCE_LOCAL JPA transaction type works.

Since this is the default transaction type when using Spring Boot or Spring Data JPA, it’s very important to understand how transactions are managed when using the RESOURCE_LOCAL mode.

JPA Transaction Types

When the JPA 1.0 specification was released, there were two transaction types you could choose from: JTA and RESOURCE_LOCAL.

JTA (Jakarta Transactions, formerly known as Java Transaction API) is a specification that allows us to use global transactions to apply modifications on multiple database connections, caches, or JMS queues in an atomic unit of work.

To use JTA, the JPA specification requires us to provide the following configuration options in the persistence.xml JPA configuration file:

  • The transaction-type attribute of the Persistence Unit we are using should be set to the value of JTA.
  • The Persistence Unit should use the jta-data-source element to provide the JNDI path where the JTA DataSource is to be located.

If you want to see how these settings would look in the traditional persistence.xml JPA configuration file, check out the following code example:

<persistence-unit name="persistenceUnit" transaction-type="JTA">
    ...
    <jta-data-source>java:global/jdbc/PostgreSQLJTADataSource</jta-data-source>
</persistence-unit>

For more details about how you can customize JPA using the persistence.xml configuration file, check out this article.

If we don’t need global transactions, JPA offers us the RESOURCE_LOCAL transaction type, which can operate with a single database connection. To choose this transaction mode, we need to set the transaction-type attribute to the value of RESOURCE_LOCAL and use a non-jta-data-source element that points to a JDBC DataSource:

<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
    ...
    <non-jta-data-source>java:comp/env/jdbc/PostgreSQLDataSource</non-jta-data-source>
</persistence-unit>

While the XML-based configuration option was convenient for Java EE application servers that were managing the Persistence Unit instantiation, Spring applications use a Java-based programmatic configuration that is enabled by the PersistenceProvider utility, which takes the JPA configuration through an instance of the PersistenceUnitInfo interface.

When using the Java-based configuration, the DataSource can be provided via the jakarta.persistence.jtaDataSource or jakarta.persistence.nonJtaDataSource settings, as illustrated by the following code examples:

properties.put(AvailableSettings.JAKARTA_JTA_DATASOURCE, jtaDataSource);
properties.put(AvailableSettings.JAKARTA_NON_JTA_DATASOURCE, jdbcDataSource);

RESOURCE_LOCAL JPA Transaction Type

When using the RESOURCE_LOCAL JPA transaction type, the JDBC Connection is used to manage the underlying database transaction via the commit and rollback methods, as illustrated by the following diagram:

RESOURCE_LOCAL JPA Transaction Type

Because the JDBC Connection uses the auto-commit mode by default, the first thing that the JPA provider will do is disable it if it wasn’t disabled previously. The database connection is bound to the current executed thread and used for all statement executions until the end of the transaction.

Afterward, all SQL statements executed by the data access layer will run within the same database transaction because they are all using the same physical database connection.

At the end of the current unit of work, if no failure was detected, the commit method will be called on the associated JDBC Connection, and the database transaction will be committed as well. If a failure is detected, the rollback method is called instead.

If you are using Spring, this logic is encapsulated in the TransactionAspectSupport class, which is the base class of the TransactionIterceptor aspect that decorates the @Transactional methods.

For example, the commitTransactionAfterReturning method handles the commit logic while the completeTransactionAfterThrowing method takes care of the transaction rollback.

If you enjoyed this article, I bet you are going to love my Book and Video Courses as well.

Conclusion

When using the RESOURCE_LOCAL JPA transaction type, the database transaction is managed by the underlying JDBC Connection.

If you are using Spring, the TransactionInterceptor is going to call commit or rollback on the underlying TransactionManager. For the RESOURCE_LOCAL JPA transaction type, Spring offers the JpaTransactionManager, while for JTA, there is a JtaTransactionManager you will have to use instead.

Transactions and Concurrency Control eBook

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.