Introduction
In enterprise applications, data correctness is more important than performance.
Consider these situations:
- Two users update the same order.
- Multiple payment requests arrive simultaneously.
- Inventory quantity is updated concurrently.
- Funds are transferred between accounts.
- Multiple microservices update the same record.
Without proper transaction management:
❌ Lost updates
❌ Dirty reads
❌ Duplicate records
❌ Inconsistent data
❌ Deadlocks
❌ Data corruption
This article covers:
✅ ACID properties
✅ Spring transactions
✅ Transaction boundaries
✅ Isolation levels
✅ Propagation
✅ Optimistic locking
✅ Pessimistic locking
✅ Deadlocks
✅ Concurrency best practices
What is a Transaction?
A transaction is a group of operations that execute as a single unit.
Example:
Transfer ₹1000
Account A -1000
Account B +1000
Both operations must succeed.
ACID Properties
| Property | Meaning |
|---|---|
| Atomicity | All or nothing |
| Consistency | Valid state |
| Isolation | Independent execution |
| Durability | Permanent storage |
Atomicity
Debit Account A
Credit Account B
If the second operation fails:
Rollback both.
Consistency
Before:
Total Balance = ₹50,000
After:
Total Balance = ₹50,000
Rules remain valid.
Isolation
Users should not interfere with each other.
Durability
After commit:
Data survives:
- Server restart
- Application crash
- Database restart
Spring Transaction Management
@Service
public class PaymentService {
@Transactional
public void transfer() {
}
}
Spring:
- Starts transaction.
- Commits on success.
- Rolls back on failure.
Transaction Lifecycle
Method starts
↓
Begin transaction
↓
Execute SQL
↓
Commit
Failure:
Exception
↓
Rollback
Example
@Transactional
public void transferMoney() {
debit();
credit();
}
Rollback Rules
By default:
RuntimeException → Rollback
Checked Exception → No rollback
Example
@Transactional(
rollbackFor = Exception.class)
Now:
- Checked exceptions rollback.
Transaction Boundaries
Good:
@Service
@Transactional
public void processOrder() {
}
Avoid:
@Repository
@Transactional
Business transactions belong to services.
Isolation Levels
| Level | Dirty Read | Non-repeatable | Phantom |
|---|---|---|---|
| Read Uncommitted | Yes | Yes | Yes |
| Read Committed | No | Yes | Yes |
| Repeatable Read | No | No | Yes |
| Serializable | No | No | No |
Read Uncommitted
Transaction A:
Update salary = 10000
Not committed.
Transaction B reads:
10000
A rolls back.
Dirty read.
Oracle does not support this.
Read Committed
Oracle default.
Only committed data is visible.
Recommended for most applications.
Repeatable Read
Same row always returns same value.
Useful for reporting.
Serializable
Highest consistency.
Lowest concurrency.
Spring Example
@Transactional(
isolation =
Isolation.READ_COMMITTED)
Propagation
Defines transaction behavior.
REQUIRED
Default.
@Transactional
Join existing transaction.
Create if absent.
REQUIRES_NEW
@Transactional(
propagation =
Propagation.REQUIRES_NEW)
Always creates a new transaction.
Example
Order Service
↓
Audit Service
Audit should commit independently.
SUPPORTS
Participates if transaction exists.
NOT_SUPPORTED
Suspends transaction.
Useful for reporting.
MANDATORY
Requires existing transaction.
Throws exception otherwise.
Propagation Summary
| Type | Description |
|---|---|
| REQUIRED | Default |
| REQUIRES_NEW | New transaction |
| SUPPORTS | Optional |
| NOT_SUPPORTED | No transaction |
| MANDATORY | Must exist |
Optimistic Locking
Assumes conflicts are rare.
Add:
@Version
private Integer version;
Example
User A:
Version = 1
User B:
Version = 1
User A updates:
Version = 2
User B updates:
OptimisticLockException
Database
VERSION NUMBER
Update:
UPDATE EMPLOYEE
SET NAME=?,
VERSION=2
WHERE ID=1
AND VERSION=1
Advantages
✅ High scalability
✅ No locks
✅ Better throughput
Pessimistic Locking
Assumes conflicts are frequent.
Example
@Lock(
LockModeType.PESSIMISTIC_WRITE)
Generated SQL:
SELECT *
FROM EMPLOYEE
WHERE EMP_ID=1
FOR UPDATE
Other users wait.
Lock Types
| Lock | Purpose |
|---|---|
| PESSIMISTIC_READ | Read lock |
| PESSIMISTIC_WRITE | Update lock |
| PESSIMISTIC_FORCE_INCREMENT | Lock + version |
When to Use Optimistic Locking
- Web applications
- Microservices
- APIs
- Low conflict systems
When to Use Pessimistic Locking
- Inventory
- Financial systems
- Seat booking
- Stock trading
Deadlocks
Example:
Transaction A:
Locks Account A
Needs Account B
Transaction B:
Locks Account B
Needs Account A
Result:
Deadlock
Oracle Deadlock Error
ORA-00060:
deadlock detected
Oracle kills one transaction.
Deadlock Prevention
Access rows consistently.
Good:
Account A
Account B
Always same order.
Keep transactions short.
Avoid user interaction inside transactions.
Bad:
Begin transaction
Display popup
Wait 30 seconds
Lost Update Problem
User A:
Salary = 10000
User B:
Salary = 10000
A saves:
12000
B saves:
11000
A’s changes lost.
Optimistic locking prevents this.
Read Only Transactions
@Transactional(
readOnly = true)
Benefits:
- Optimization.
- Prevents updates.
Transaction Timeout
@Transactional(
timeout = 30)
Rollback after 30 seconds.
Nested Transactions
Spring does not fully support true nested transactions.
Use:
REQUIRES_NEW
Example Service
@Service
public class OrderService {
@Transactional
public void placeOrder() {
saveOrder();
savePayment();
saveShipment();
}
}
Everything commits together.
Event Publishing
Bad:
@Transactional
public void save() {
publishEvent();
insert();
}
Event may publish before rollback.
Good:
@TransactionalEventListener
After commit.
Distributed Transactions
Multiple systems:
- Payment
- Inventory
- Shipping
Avoid:
2PC
Prefer:
- Saga pattern
- Event-driven architecture
Monitoring Transactions
Look for:
- Long transactions
- Deadlocks
- Blocking sessions
- Rollbacks
Oracle views:
V$TRANSACTION
V$LOCK
V$SESSION
Common Mistakes
Transaction on Controller
Bad.
Large Transactions
Bad.
Missing Version Column
Bad.
Long Running Transactions
Bad.
Pessimistic Everywhere
Bad.
Recommended Strategy
| Scenario | Recommendation |
|---|---|
| CRUD application | Optimistic |
| Inventory | Pessimistic |
| Banking | Pessimistic |
| APIs | Optimistic |
| Reporting | Read-only |
Interview Questions
Difference between optimistic and pessimistic locking?
Optimistic assumes low conflicts.
Pessimistic locks rows.
What is Oracle default isolation?
READ_COMMITTED.
What causes deadlocks?
Circular waiting.
Why use @Version?
Prevent lost updates.
What is propagation?
Transaction behavior between methods.
Why use readOnly?
Performance optimization.
Best Practices
✅ Put transactions in services.
✅ Keep transactions short.
✅ Use optimistic locking.
✅ Add version columns.
✅ Use read-only transactions.
✅ Avoid user interaction.
✅ Monitor deadlocks.
✅ Use timeouts.
Summary
This article covered:
✅ ACID
✅ Spring transactions
✅ Isolation levels
✅ Propagation
✅ Optimistic locking
✅ Pessimistic locking
✅ Deadlocks
✅ Lost updates
✅ Transaction monitoring
Next Article
Part 10 – Production Best Practices, Performance and Enterprise Architecture
Topics:
- Schema standards
- Audit columns
- Soft deletes
- Connection pool tuning
- Index strategies
- Pagination
- Flyway and Liquibase
- Monitoring
- Logging
- Production troubleshooting
- Enterprise architecture