Mastering Spring Transaction Management: Best Practices and Strategies


What is transaction management, for example let’s say a money transaction is going to take place between two parties now, in order to have a successful transaction two instructions need to take place:

  1. The source balance must be decreased. 
  2. The receiver balance must be increased.

If any one of the instructions failed, the other also needed to be stopped or else it will be a faulty transaction. In our day-to-day transactions this phenomenon occurs.

So, in simple terms, what the transaction management does is, it executes all the transactions or none of them will get executed. Transactions are atomic and ensure the database’s data remains consistent despite failure or errors.

ACID PROPERTIES OF A TRANSACTION:

Atomicity: Atomicity, a fundamental concept in database transactions, ensures that a sequence of operations is treated as a single unit. Either the entire transaction is successfully completed, or if any part fails, the entire transaction is reverted to its previous state, preserving database consistency. For instance, in a financial transaction involving the transfer of funds between accounts, both operations must be executed within a single unit of work to guarantee data integrity.

Consistency:Consistency is a fundamental property that ensures all data written to the database adheres to the established rules and constraints. It guarantees the validity and accuracy of data, reflecting real-world relationships between entities. A transaction serves as a mechanism to transition the database from one consistent state to another.

Isolation: Isolation is a crucial database property that ensures concurrent transactions do not interfere. It guarantees that each transaction is executed independently, as if it were the sole operation occurring, even in the presence of multiple simultaneous transactions. This mechanism is essential to prevent inconsistencies and maintain data integrity. In Relational Database Management Systems (RDBMS), four primary isolation levels are commonly used. These levels, typically arranged in ascending order of restrictiveness, are Read Uncommitted, Read Committed, Repeatable Read, and Serializable. Among these, Read Committed stands as the default isolation level, proving adequate for most use cases. However, the selection of an appropriate isolation level should be carefully considered based on the specific requirements of the application. It is important to note that performance considerations are inversely proportional to the level of isolation implemented. Higher isolation levels may introduce additional overhead and potentially impact system performance. Therefore, striking a balance between isolation and performance is essential to optimize database operations and ensure both data integrity and efficient system functioning.

Durability:Durability is the characteristic that guarantees that once a transaction has been committed (i.e., completed and saved), it will not be lost even in the event of a system failure. This is typically achieved through logs and backups, which enable the database to be restored to a known, functional state in case of a failure. 

In summary, the ACID properties are fundamental to preserving the integrity and reliability of a database. They ensure that transactions are atomic, consistent, isolated, and durable, which are essential requirements for any DBMS.

The actual working of the transaction management would be like once the transaction begins the queries execute one by one, but it won’t reflect over the database yet. Once all the queries are completed ‘commit’ command will get executed then all these queries will get executed and data will be reflected onto the database. The start of the transactions is ‘begin’, then the transactions will take place and finally ‘commit’ to make changes in the database. If there is no transaction management the default mode is ‘auto commit on’.

Begin
Query1
Query2
Query3
Commit

The @Transactional annotation is used to mark a method or a class as transactional, meaning that any database operations performed within the marked method or class will be executed within a transaction. If the transaction is successful, the changes will be committed to the database. If an error occurs and the transaction is rolled back, the changes will not be persisted in the database. The default propagation is ‘REQUIRED’.

Propagations:

The default propagation is REQUIRED, it will be applied if not provided explicitly.

There are a total of 6 propagations:

PropagationBehavior
REQUIREDAlways executes in a transaction. If there is any existing transaction it uses it. If none exists, then only a new one is created
SUPPORTSIt may or may not run in a transaction. If a current transaction exists, it will take place in that transaction or else it will run without the transaction.
NOT_SUPPORTEDAlways executes without a transaction. As the name says it will not use any existing transaction and it will not create any new transaction. Even if there is any previous transaction it will suspend that before executing this and resume once done
REQUIRES_NEWAlways executes in a new transaction. Irrespective of the previous transaction, i.e. even if it’s there or not a new transaction will be created.
NEVERAlways executes without any transaction. It’s more like NOT_SUPPORTED but it also throws an exception if there is any existing transaction.
MANDATORYAlways executes in a transaction. It always uses an existing transaction. If there isn’t any existing transaction it will throw an exception.

ISOLATION LEVELS:

1. DEFAULT

  • Uses the default isolation level of the underlying database.

2. READ_UNCOMMITTED

  • Allows dirty reads, meaning that changes made by one transaction can be read by other transactions before being committed.
  • This level provides the highest performance but the lowest data consistency.

3. READ_COMMITTED

  • Prevents dirty reads by allowing other transactions to read only committed changes.
  • This level provides a balance between performance and consistency.

4. REPEATABLE_READ

  • Ensures that if a value is read multiple times within the same transaction, the result will always be the same, if it hasn’t been changed by the same transaction.
  • This level provides higher consistency but may impact performance.

5. SERIALIZABLE

  • Ensures complete isolation from other transactions, meaning that transactions are executed in a way that produces the same outcome as if they were executed serially.
  • This level provides the highest consistency but may have a significant impact on performance.