Stage 8 - Transactions: ACID, @Transactional, Rollback, and Isolation
A transaction is the boundary where several database changes become one complete operation. The classic example is a bank transfer. If money is subtracted from account A but not added to account B, the data is corrupted. A transaction makes the operation atomic: both changes commit, or both changes roll back.
ACID
ACID describes four properties of reliable transactions. Atomicity means all steps are treated as one unit. Consistency means the database moves from one valid state to another valid state. Isolation means concurrent transactions do not interfere in ways that violate the selected isolation rules. Durability means committed changes survive crashes.
| Transfer step | What can go wrong without a transaction | Which ACID idea protects it |
|---|---|---|
| Subtract money from account A | The debit is saved, but the credit to account B fails. | Atomicity makes both updates commit together or roll back together. |
| Check that balance cannot become negative | A rule is bypassed and the database stores an invalid state. | Consistency keeps the operation inside valid business and database rules. |
| Two transfers touch the same account | One operation reads an intermediate or stale value from another. | Isolation controls what concurrent transactions are allowed to see. |
| Commit succeeds and the app crashes | The user sees success, but the data disappears after restart. | Durability means committed changes are persisted. |
@Transactional in Spring
In Spring applications, @Transactional is usually placed on service methods. A service method describes a complete use case, so it is the natural transaction boundary. The controller should not own the transaction because it handles HTTP. The repository should not own the full business transaction because one use case may call several repositories.
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
Account from = accountRepository.findById(fromId).orElseThrow();
Account to = accountRepository.findById(toId).orElseThrow();
from.withdraw(amount);
to.deposit(amount);
}
When the method starts, Spring opens a transaction. Loaded entities become managed. When fields change, Hibernate tracks those changes. If the method finishes normally, Spring commits and Hibernate flushes SQL. If a runtime exception is thrown, Spring rolls back by default.
Rollback
Automatic rollback usually happens for unchecked exceptions. Checked exceptions do not trigger rollback by default unless configured. This matters when service methods throw business exceptions. You can use rollbackFor when the default is not enough, but do not configure rollback randomly. The exception model should match the domain operation.
Manual rollback exists, but it is rarely the first choice. Clear exceptions and declarative transactions are easier to read and test.
Isolation levels and propagation
Isolation controls how one transaction sees changes from other transactions. READ_UNCOMMITTED is weakest and allows dirty reads in databases that support it. READ_COMMITTED prevents dirty reads and is a common default. REPEATABLE_READ keeps rereads stable within a transaction. SERIALIZABLE is strongest and behaves closest to running transactions one at a time, but it can reduce concurrency.
Propagation controls what happens when a transactional method calls another transactional method. REQUIRED joins an existing transaction or creates one. It is the common default. REQUIRES_NEW suspends the current transaction and starts a new one. SUPPORTS joins a transaction if one exists but can run without one.
Practice
Implement a money transfer between accounts. Load both accounts inside one @Transactional service method, subtract from one balance, add to the other, and throw an exception after the first change to demonstrate rollback. Then remove the exception and verify both balances commit together. Finally, inspect SQL logs and confirm that updates are flushed at commit.
Understanding checklist
- I can explain transaction boundaries with a bank transfer.
- I know the four ACID properties.
- I understand why
@Transactionalbelongs on service methods. - I can explain default rollback behavior.
- I know the basic meaning of isolation and propagation.