Transactions in Spring#
Introduction#
In any real-world application, especially when interacting with databases, managing data integrity is crucial. Transactions allow us to ensure that a group of operations are executed in an "all-or-nothing" fashion. This means that if one operation fails, all changes made by other operations in the transaction should be rolled back, leaving the system in a consistent state.
What is a Transaction?#
A transaction is a sequence of operations that are treated as a single unit of work. These operations either succeed together or fail together. For example, in a banking system, transferring money from one account to another involves debiting one account and crediting another. Both operations must succeed, or neither should be completed.
Why Do We Need Transactions?#
Without transactions, partial operations could leave the system in an inconsistent state, resulting in data corruption or loss. Transactions ensure:
- Atomicity: All operations in a transaction are completed successfully, or none at all.
- Consistency: The system remains in a valid state before and after the transaction.
- Isolation: Transactions occur independently, without interference.
- Durability: Once a transaction is committed, the changes are permanent, even if the system crashes.
@Transactional Annotation in Spring#
Spring provides the @Transactional
annotation to handle transactions declaratively. When a method is annotated with @Transactional
, Spring manages the transaction automatically.
How Does @Transactional Work?#
- Begin Transaction: When the annotated method is called, Spring opens a new transaction.
- Commit or Rollback: If the method executes successfully, the transaction is committed, and changes are saved. If an exception occurs, the transaction is rolled back, and changes are discarded.
Example: Using @Transactional#
Let's walk through a simple example of managing a transaction in a service layer.
Entity Classes#
We have two entities, Account
and TransactionRecord
. When we transfer money, both entities need to be updated.
Service Class with Transaction Management#
Explanation:#
- The
@Transactional
annotation ensures that all operations within thetransferMoney
method (debit, credit, and recording the transaction) are executed within a single transaction. - If any operation fails (e.g., saving the transaction record), the entire transaction is rolled back, leaving the accounts unchanged.
Transaction Propagation and Isolation Levels#
- Propagation: Defines how transactions behave in nested method calls. For example,
Propagation.REQUIRED
means that the method should run within a transaction; if one doesn't exist, a new transaction is started.
- Isolation Levels: Control how changes made by one transaction are visible to other transactions. Spring provides various isolation levels like
READ_COMMITTED
,REPEATABLE_READ
, andSERIALIZABLE
.
Dirty Read - A Dirty read is a situation when a transaction reads data that has not yet been committed.
Non Rpeatable Read - Non Repeatable read occurs when a transaction reads the same row twice and gets a different value each time.
Phantom Read - Phantom Read occurs when two same queries are executed, but the rows retrieved by the two, are different.
Key Points#
- Use
@Transactional
at the service layer where business logic and database operations are managed. - By default,
@Transactional
rolls back onRuntimeExceptions
or unchecked exceptions. - Transactions ensure data consistency and integrity, making them crucial in systems that handle financial operations, order processing, and more.
In this article, we examined the importance of transactions in Spring and how they ensure data integrity in applications interacting with databases. We defined transactions as sequences of operations that are treated as a single unit of work, emphasizing the need for atomicity, consistency, isolation, and durability (ACID properties).