Transaction Management in Spring Boot ensures that multiple database operations behave as a single logical unit of work.
If all operations succeed → COMMIT If any operation fails → ROLLBACK
This guarantees data consistency and integrity.
Bank Transfer Example Step 1: Debit amount from Account A Step 2: Credit amount to Account B
Either BOTH succeed OR BOTH fail
| Property | Meaning |
|---|---|
| Atomicity | All operations succeed or all fail |
| Consistency | Database remains in valid state |
| Isolation | Transactions do not interfere |
| Durability | Committed data is permanent |
Transaction Start ↓ Update Account A ↓ Update Account B ↓ Commit
Transaction Start ↓ Update Account A ↓ Error occurs ↓ Rollback
Client ↓ Service Layer ↓ @Transactional Proxy ↓ Transaction Manager ↓ Repository / DAO ↓ Database
| Layer | Responsibility |
|---|---|
| Client | Calls service method |
| Service | Contains business logic |
| Transaction Proxy | Handles transaction boundaries |
| Transaction Manager | Begins / commits / rollbacks |
| Repository | Executes SQL |
| Transaction Manager | Used With |
|---|---|
| DataSourceTransactionManager | JDBC |
| JpaTransactionManager | JPA / Hibernate |
| HibernateTransactionManager | Hibernate |
| JtaTransactionManager | Distributed transactions |
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
The @Transactional annotation enables transaction management.
@Service
public class PaymentService {
@Transactional
public void transferMoney(Long fromId, Long toId, double amount) {
accountRepository.debit(fromId, amount);
accountRepository.credit(toId, amount);
}
}
Start Transaction
↓
Debit Account
↓
Credit Account
↓
Success → COMMIT
Failure → ROLLBACK
@Entity
public class Account {
@Id
@GeneratedValue
private Long id;
private String name;
private double balance;
}
@Repository
public interface AccountRepository extends JpaRepository {
}
@Service
public class AccountService {
@Autowired
private AccountRepository accountRepository;
@Transactional
public void transfer(Long fromId, Long toId, double amount) {
Account fromAccount = accountRepository.findById(fromId).orElseThrow();
Account toAccount = accountRepository.findById(toId).orElseThrow();
fromAccount.setBalance(fromAccount.getBalance() - amount);
toAccount.setBalance(toAccount.getBalance() + amount);
accountRepository.save(fromAccount);
accountRepository.save(toAccount);
}
}
| Propagation Type | Description |
|---|---|
| REQUIRED | Join existing transaction or create new |
| REQUIRES_NEW | Always create new transaction |
| SUPPORTS | Use existing transaction if available |
| NOT_SUPPORTED | Run without transaction |
| MANDATORY | Must run inside transaction |
| NEVER | Must run without transaction |
| NESTED | Nested transaction |
@Transactional(propagation = Propagation.REQUIRED)
public void processOrder(){
}
| Isolation Level | Description |
|---|---|
| READ_UNCOMMITTED | Dirty reads allowed |
| READ_COMMITTED | Only committed data |
| REPEATABLE_READ | Same row returns same result |
| SERIALIZABLE | Highest isolation |
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateInventory(){
}
Rollback occurs for: RuntimeException Error
@Transactional(rollbackFor = Exception.class)
public void processPayment() throws Exception{
}
✔ Keep transactions in Service Layer ✔ Use @Transactional at method level ✔ Keep transactions short ✔ Use readOnly for queries ✔ Avoid transactions in Controller
What annotation enables transactions?
@Transactional
Default propagation?
REQUIRED
Where should transactions be used?
Service Layer