Spring Boot Transaction Management
Hi there. I’m going to explain transaction management in this article using Spring Boot.
1. What is the meaning of Spring Boot Transaction?
In Spring Boot, a transaction manages the database operations of a particular method as a whole. This enables us to handle rollbacks of all transactions in case of any errors during the transaction, ensuring data integrity and consistency. Transaction management automatically initiates and manages database transactions, either committing or rolling back the transaction. This increases the reliability and data integrity of the application.
While most developers use only @Transactional but propagation types are the most important part of this annotation.
2. What are the propagations?
In Spring Boot, transaction propagation defines how the operation inside a method behaves. For example, if one process calls another, propagation settings determine which process continues. Through predefined propagation levels, the process can join another or create its own transaction. This allows controlling transaction behavior and managing the interaction of database transactions.
Before explaining propagation levels, we should understand how Spring Boot manages methods and handles exceptions in @Transactional methods.
Spring Boot uses aspects to handle transactional methods. We should understand how does it work (from official docs).
RuntimeException triggers the rollback mechanism. Let’s see how it affects propagations.
Let’s explain propagation types:
1- @Transactional(propagation = Propagation.REQUIRED):
It’s the default propagation type. If there is already a transaction, it joins the existing one; if not, it creates a new one. Generally, we use it in upper methods.
2- @Transactional(propagation = Propagation.REQUIRES_NEW):
If there is a transaction, it suspends and opens a new one, making it independent of any existing transaction. If an exception occurs in this transaction, it doesn’t affect other transactions (if the exception is handled in other transactions). Generally, we use it for separate processes.
3- @Transactional(propagation = Propagation.SUPPORTS):
If a transaction exists, it behaves like the existing one. If not, it acts as non-operational. The difference between a non-transactional method and this propagation is the use of Aspect. Thus, if this method throws RuntimeException, and even if this exception is caught in upper methods, the rollback mechanism will be triggered, rolling back everything belonging to the current transaction. Generally, we use it for transaction saving.
4- @Transactional(propagation = Propagation.NOT_SUPPORTED):
It behaves non-transactional. If there is a transaction, it suspends it. Generally, we use it for logging processes.
5- @Transactional(propagation = Propagation.MANDATORY):
It requires a transaction. If there is no existing transaction, it throws an exception. Generally, we use it to create hierarchical transactions.
6- @Transactional(propagation = Propagation.NEVER):
If there is an existing transaction, it throws an exception. Generally, we use it to prevent another process from being used inside the current process.
7- @Transactional(propagation = Propagation.NESTED):
If there is an existing transaction, it suspends and opens a new one. It behaves like Propagation.REQUIRES_NEW, but with some differences. If the nested transaction succeeds, Spring doesn’t commit it immediately. Instead, Spring waits for the parent transaction, and if it succeeds, Spring commits the nested transaction. Generally, we use it for complex flows.
Now you can manage your transactions more accurately. I’m going to share Isolation levels in next article.