Part 1 — Understanding Transaction Management in Spring Boot
1. Introduction
Part 1 — Understanding Transaction Management in Spring Boot
1. Introduction
In modern backend applications, multiple database operations often need to be executed together as a single unit. If one operation fails, the entire set of operations should be rolled back to maintain data consistency.
This is where transactions play an important role.
Imagine you’re building a banking system. A user transfers money from account A to account B. The system deducts the amount from A and adds it to B. Now, what if the second operation fails? Money is deducted, but never credited — your data is inconsistent. This is exactly why transactions exist.

Spring Boot provides a powerful and easy way to handle such scenarios with the @Transactional annotation. But how does it work under the hood? And where should you place it?
In this article, we’ll explore:
- What a transaction is
- The ACID properties that define transactions
- Why we need transactions
- How Spring manages transactions with
@Transactional - Best practices for placing transaction boundaries
- A peek into transaction propagation and isolation (preview)
By the end, you’ll have a solid foundation for building reliable, data‑consistent applications. Let’s dive in! 🚀
2. What is a Transaction?
A transaction is a sequence of one or more database operations that are treated as a single logical unit of work.
A transaction guarantees that:
- All operations succeed → Commit
- Any operation fails → Rollback
Example scenario: Transfer money between two bank accounts
- Deduct money from Account A
- Add money to Account B
If step 2 fails but step 1 succeeds, the system becomes inconsistent. Transactions ensure both operations succeed together or both fail.
3. ACID Properties of Transactions
Transactions follow four key properties known as ACID.
Atomicity Atomicity ensures that all operations in a transaction succeed or none of them do. Example: Debit account A, credit account B. If one fails, both are rolled back.
Consistency Consistency ensures that the database moves from one valid state to another valid state. Example: Total balance in the system should remain correct after a transfer
Isolation Isolation ensures that multiple transactions running at the same time do not interfere with each other. Example: Two users transferring money simultaneously should not corrupt account balances.
Durability Once a transaction is committed, the changes are permanently stored in the database even if the system crashes.
4. Why Transactions Are Needed
Transactions help maintain data integrity and consistency when performing database operations.
Common scenarios where transactions are necessary:
- Financial transfers
- Order creation with order items
- Updating multiple related tables
- Event publishing after database changes
Example:
- Create Order
- Insert order
- Insert order items
- Update inventory
If any step fails, the entire operation must be rolled back.

5. Getting Started: Transaction Management in Spring Boot
Spring Boot simplifies transaction management using the @Transactional annotation.
First, ensure you have the necessary dependency in your project (if you’re using Maven):
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
This starter brings in Hibernate and Spring’s transaction management capabilities.
Note: Spring Boot automatically enables transaction management for you. In a core Spring Framework project, you would need to add
@EnableTransactionManagementon a configuration class.
Basic Example:
Let’s see a simple service that updates an employee’s address:
@Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
public EmployeeService(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
@Transactional
public void updateEmployeeAddress(Long id, String newAddress) {
Employee employee = employeeRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Employee not found"));
employee.setAddress(newAddress);
// When the method exits, Hibernate will automatically flush the change to the DB
}
}
The repository interface is straightforward:
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
What happens internally:
- Transaction starts before the method executes.
- Database operations (find, then update on flush) execute.
- If successful → commit.
- If any
RuntimeException(or checked exception configured for rollback) occurs → rollback.
Spring handles all of this automatically.
6. Where Should @Transactional Be Used?
In a typical Spring Boot application, transactions should be defined at the service layer.
Architecture:

Best practice:
- Controller: Handles HTTP requests
- Service: Contains business logic and transaction boundaries
- Repository: Database access
Example: Order creation with multiple repositories
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final OrderItemRepository orderItemRepository;
private final InventoryService inventoryService;
public OrderService(...) { ... }
@Transactional
public void createOrder(OrderRequest request) {
Order order = new Order(request);
orderRepository.save(order);
List<OrderItem> items = request.getItems();
orderItemRepository.saveAll(items);
inventoryService.updateStock(items); // might throw exception
}
}}
If inventoryService.updateStock() throws a runtime exception, both the order and order items saved so far will be rolled back. This is the atomicity guarantee in action.
7. When Transactions Are Typically Used
Transactions are commonly used for:
- Insert operations
- Update operations
- Delete operations
- Multiple dependent database operations
Using @Transactional(readOnly = true) for Read Operations
In many applications, you’ll see service methods annotated with:
@Transactional(readOnly = true)
public Employee getEmployee(Long id) {
return employeeRepository.findById(id).orElseThrow();
}
This tells Spring and Hibernate that the method is intended only for reading data, not modifying it.
Benefits:
- Hibernate optimization: It sets the Hibernate
FlushModetoMANUAL, preventing the dirty checking mechanism from triggering. This avoids unnecessary snapshots and comparisons. - Database optimization: Some databases can use this hint to optimize read-only queries or even route them to read replicas if your connection pool supports it.
- Lazy loading support: The transaction keeps the Hibernate session open, allowing lazy associations to be initialized without throwing a
LazyInitializationException.
For simple read operations that do not involve entity relationships or modifications, @Transactional(readOnly = true) is optional but recommended as a best practice.
We will explore concepts like dirty checking and lazy loading in detail in later articles in this series.
8. Common Interview Questions
Q1: What is a transaction? A: A logical unit of work that guarantees atomicity, consistency, isolation, and durability (ACID).
Q2: Where should you place @Transactional in a Spring Boot app?
A: In the service layer, because it groups related business operations and keeps controllers clean.
Q3: What happens when a method annotated with @Transactional throws an exception?
A: By default, Spring rolls back the transaction if a RuntimeException or Error occurs. Checked exceptions do not trigger rollback (can be overridden with rollbackFor).
Q4: Why use @Transactional(readOnly = true)?
A: It optimizes performance by disabling dirty checking and setting flush mode to MANUAL. It also communicates intent to other developers.
Key Takeaways
- Transaction : Unit of work that ensures all operations succeed or none.
- ACID : Atomicity, Consistency, Isolation, Durability.
- @Transactional : Spring annotation to mark a transaction boundary.
- Service Layer : The correct place to put transactions.
- readOnly = true : Optimizes read‑only operations.
- Rollback : Default for runtime exceptions; use
rollbackForfor checked exceptions
🧠 Quick Challenge for You!
Consider the following code:
@Service
public class PaymentService {
@Transactional
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
Account from = accountRepository.findById(fromId).orElseThrow();
Account to = accountRepository.findById(toId).orElseThrow();
from.setBalance(from.getBalance().subtract(amount));
to.setBalance(to.getBalance().add(amount));
// Assume a runtime exception occurs here
throw new RuntimeException("Unexpected error");
}
}
Questions:
- Will the balances be updated in the database?
- What would happen if the exception was a checked
SQLException(with default settings)? - How could you make the transaction rollback on a checked exception?
👇 Drop your answers in the comments below! This scenario appears in many interviews.
💬 Let’s Discuss!
- Have you ever had a transaction not roll back when you expected it to?
- What’s your favorite Spring transaction feature?
- Do you have any questions about
@Transactionalor transaction management?
Leave a comment below — let’s learn together! 👇
🔜 What’s Next?
In the next article, we’ll dive deep into the internals of @Transactional:
👉 **How @Transactional Works Internally (AOP & Proxy Explained)**
We’ll cover:
- How Spring uses AOP and proxies to manage transactions
- The role of the
TransactionManager - JDK dynamic proxy vs CGLIB
- Why self‑invocation breaks transactions (and how to avoid it)
📚 Spring Transactions & Hibernate Internals Series
- Part 1 — Transaction Management in Spring Boot 👈you are here
- Part 2 — How @Transactional Works Internally in Spring Boot
- Part 3 — The Self Invocation Problem in Spring Transactions
- Part 4 — Understanding Hibernate Persistence Context
- Part 5 — Dirty Checking in Hibernate
- Part 6 — Flush vs Commit in Hibernate
- Part 7 — Lazy Loading vs Eager Loading in Hibernate
- Part 8 — The N+1 Query Problem in Hibernate
- Part 9 — Interview Q&A
메타데이터
- post_id
- e091ea341d8c
- slug
- understanding-transaction-management-in-spring-boot-e091ea341d8c
- url
- https://medium.com/@varuntewani01/understanding-transaction-management-in-spring-boot-e091ea341d8c
- canonical_url
- https://medium.com/@varuntewani01/understanding-transaction-management-in-spring-boot-e091ea341d8c
- author_url
- https://medium.com/@varuntewani01
- status
- ok
- fetched_at
- 2026-07-13 06:23:13