Spring's transaction management with the @Transactional annotation

  • 4.4/5
  • 5467
  • Jul 20, 2024

What is a database transaction?

A database transaction is any operation that is treated as a single unit of work that either completes fully or does not complete at all and leaves the storage system in a consistent state.

Transactions can impact a single record or multiple records.

A.C.I.D. properties

ACID is an acronym that stands for atomicity, consistency, isolation, and durability.

ACID properties ensure that a database transaction (a set of read, write, update, or delete operations) leaves the database in a consistent state even in the event of unexpected errors.

1) Atomicity

Atomicity guarantees that all the commands in a transaction (to read, write, update, or delete data) are treated as a single unit and either succeed or fail together.

The transaction would have either completed successfully or been rolled back if any part of it failed.

2) Consistency

Consistency guarantees that the data is in a consistent state when a transaction starts and when it ends.

If the data gets into an illegal state, the whole transaction fails.

3) Isolation

Isolation ensures that the intermediate state of a transaction is invisible to other transactions.

As a result, transactions that run concurrently don't interfere with each other.

4) Durability

Durability guarantees that once the transaction commit and changes are written to the database, they will persist even in the case of system failures like crashes or power outages.

As a result, the transaction's modifications are never undone.

Spring Transaction Management

Spring transaction management simply means: How does Spring start, commit, or rollback JDBC transactions.

Spring provides both declarative (@Transactional) and programmatic (using a TransactionTemplate or PlatformTransactionManager) transaction management, and developers can choose based on the requirement.

Declarative transaction management is easier and more suitable in most cases, but in some cases, you want fine-grain control, and you can use programmatic transaction management.

In order to support transactions in a spring project, you need to add @EnableTransactionManagement to a @Configuration class.

However, if we're using a Spring Boot project and have spring-data-* or spring-tx dependencies on the classpath, then transaction management will be enabled by default.

The @Transactional Annotation

Any bean or public method annotated with the @Transactional annotation makes sure that the methods will be executed inside a database transaction.

The @Transactional annotation should be used in the service layer because it is this layer's responsibility to define the transaction boundaries.

The modern Spring approach to transaction management is typically as follows:

That's it! No configuration, no XML, and no code are needed.

How does the @Transactional annotation work ?

Spring creates dynamic proxies for classes that declare @Transactional on the class itself or on methods.

It does that through a method called proxy-through-subclassing with the help of the Cglib library.

It is also worth noting that the proxy itself does not handle these transactional states (open, commit, close); the proxy delegated this work to a transaction manager.

The proxy has access to a transaction manager and can ask it to open and close transactions and connections.

Spring offers a PlatformTransactionManager (extends TransactionManager) interface, which, by default, comes with a couple of handy implementations. One of them is the DataSourceTransactionManager.

Pitfalls

As Spring wraps the bean in the proxy, only calls from "outside" the bean are intercepted. That means, any self-invocation calls will not start any transaction, even if the method has the @Transactional annotation.

Moreover, only public methods should be annotated with @Transactional. Methods of any other visibility will silently ignore the annotation, as these are not proxying.

The same is true for other annotations, such as @Cacheable.

Transaction Rollback

By default, only RuntimeException and Error trigger a rollback. A checked exception does not trigger a rollback of the transaction.

The @Transactional annotation, on the other hand, supports rollbackFor or rollbackForClassName attributes for rolling back transactions, as well as noRollbackFor or noRollbackForClassName attributes for avoiding rollback.

The @Transactional annotation attributes

The @Transactional annotation provides the following attributes:

1) Propagation

The "propagation" attribute defines how the transaction boundaries propagate to other methods that will be called either directly or indirectly from within the annotated block.

There are a variety of propagation modes that can be plugged into the @Transactional method.

                                                                                               
PropagationMeaning
REQUIREDThis is the default propagation. In this case, if no active transaction is found, spring creates one. Otherwise, the method appends to the currently active transaction:
SUPPORTSIf a transaction exists, then the method uses this existing transaction. If there isn't a transaction, it is executed non-transactional.
MANDATORYIf there is an active transaction, then it will be used. If there isn't an active transaction, then Spring throws an exception.
REQUIRES_NEWSpring suspends the current transaction if it exists and then creates a new one.
NOT_SUPPORTEDIf a current transaction exists, first Spring suspends it, and then the method runs without a transaction.
NEVERSpring throws an exception if there's an active transaction.
NESTEDSpring checks if a transaction exists, and if so, it marks a save point. If method execution throws an exception, then the transaction rolls back to this save point.
2) ReadOnly

The "readOnly" attribute defines if the current transaction is read-only or read-write.

It's a good practise to set the readOnly attribute to true at the class level and override it on a per-method basis for the methods that need to write to the database.

3) RollbackFor and RollbackForClassName

The "rollbackFor" and "rollbackForClassName" attributes define one or more Throwable classes for which the current transaction will be rolled back.

By default, only RuntimeException and Error trigger a rollback. A checked exception does not trigger a rollback of the transaction.

4) NoRollbackFor and NoRollbackForClassName

The "noRollbackFor" and "noRollbackForClassName" define one or more Throwable classes for which the current transaction will not be rolled back.

5) Isolation

The "isolation" attribute describes how changes applied by concurrent transactions are visible to each other.

Source Code: GitHub

Index
How to Implement PostgreSQL Full-Text Search with Spring Boot

15 min

Spring's transaction management with the @Transactional annotation

9 min

Spring Boot Rest APIs with PostgreSQL (Spring Boot + Rest APIs)

15 min

Caching in Spring Boot (@Cacheable, @CacheEvict & @CachePut)

21 min

Declarative REST Client in Spring Boot (Spring 6 HTTP Interface)

13 min

Circuit Breaker in Spring Boot (Spring Cloud Circuit Breaker + Resilience4j)

12 min

Handling Concurrent Service Calls in a Spring Boot Application: Asynchronous vs. Reactive Approaches

11 min

Profiling a Spring Boot application with Pyroscope

7 min

Service discovery in Spring Boot (Spring Cloud + Netflix Eureka)

9 min

Dockerize Spring Boot app and Push image to DockerHub (Spring Boot + DockerHub)

4 min

Creating a Jenkins Pipeline for Spring Boot application

2 min

Monitoring Microservices (Spring Boot + Micrometer + Prometheus + Grafana)

7 min

Edge Server Pattern in Microservices (Spring Cloud Gateway)

7 min

Circuit Breaker Pattern in Microservices (Spring BOOT + Resilience4j)

4 min

Spring Cloud config server setup with Git

8 min

Distributed Tracing in Microservices (Spring Cloud Sleuth + Zipkin)

9 min

Circuit Breaker Pattern with Resilience4J in a Spring Boot Application

24 min

Deploying Spring Boot microservices on Kubernetes Cluster

12 min

Reactive programming in Java with Project Reactor

50 min

Spring Reactive with PostgreSQL (Spring Boot WebFlux + PostgreSQL)

13 min

Spring Reactive, Thymeleaf Hello World (Spring Webflux + Thymeleaf + JS/CSS)

9 min

Problem JSON (application/problem+json) in Spring WebFlux

15 min

Spring Boot Login/Logout (Spring Security + MySql + Thymeleaf)

21 min

Securing Server-to-Server Communication with "Spring Boot" & "OAuth 2"

18 min

Integrating Elasticsearch with a Spring Boot and PostgreSQL application

16 min

Sending Emails in Spring Boot via SMTP

7 min

How to create a basic Spring 6 project using Maven

5 min

Spring Boot, Thymeleaf Hello World (Spring Boot + Thymeleaf + JS/CSS)

9 min