How Does @Transactional Work Internally in Spring Boot? (Complete Interview Guide with Real E-commerce Example)
If you're preparing for Java Backend interviews at companies like Oracle, Walmart, Microsoft, Amazon, Deloitte, or any product-based company, one question that frequently comes up is: "How doesβ¦
If you’re preparing for Java Backend interviews at companies like Oracle, Walmart, Microsoft, Amazon, Deloitte, or any product-based company, one question that frequently comes up is:
“How does
@Transactionalwork internally?”
Many developers know that it commits or rolls back database changes, but interviewers often want to understand what happens behind the scenes.
In this article, we’ll explore:
- What
@Transactionalis - How it works internally
- The Spring components involved
- A real e-commerce example
- Why self-invocation doesn’t work
- Monolith vs Microservices usage
- Common interview questions
Let’s begin.
What is @Transactional?
@Transactional is a Spring annotation used to manage database transactions automatically.
Its primary goal is to ensure that a group of database operations either:
- All succeed (Commit), or
- All fail (Rollback)
This maintains the ACID properties of a transaction and keeps your database consistent.
A Real E-commerce Example
Suppose a customer places an order.
To complete the order, your application performs three operations:
- Save the Order
- Save the Payment details
- Clear the Customer’s Cart
@Service
public class OrderService {
@Transactional
public void placeOrder(OrderRequest request) {
orderRepository.save(order);
paymentRepository.save(payment);
cartRepository.clearCart(userId);
}
}
Imagine the following happens:
- Order is saved successfully.
- Payment is saved successfully.
- While clearing the cart, an exception occurs.
Without a transaction:
β
Order Saved
β
Payment Saved
β Cart Not Cleared
Now your database is inconsistent.
With @Transactional, Spring rolls back all previous changes, resulting in:
β Order Removed
β Payment Removed
β Cart remains unchanged
Everything is restored to its previous state.
How Does @Transactional Work Internally?
The biggest misconception is that Spring somehow modifies your method.
It doesn’t.
Instead, Spring uses AOP (Aspect-Oriented Programming) and the Proxy Pattern.
The actual flow looks like this:
Client
β
βΌ
Spring Proxy
β
βΌ
TransactionInterceptor
β
βΌ
PlatformTransactionManager
β
βΌ
Connection.setAutoCommit(false)
β
βΌ
Business Method
β
βββ Success β Commit
βββ Exception β Rollback
Let’s understand each step.
Step 1: Spring Detects @Transactional
When the application starts, Spring scans all beans.
Whenever it finds:
@Transactional
public void placeOrder() {
}
it doesn’t expose the actual object.
Instead, it creates a Proxy Object.
Instead of:
Client
β
βΌ
OrderService
Spring creates:
Client
β
βΌ
OrderService Proxy
β
βΌ
OrderService
This proxy intercepts every method call.
Step 2: Client Calls the Method
Suppose the controller executes:
orderService.placeOrder();
The call does not directly reach OrderService.
Instead:
Controller
β
Spring Proxy
β
OrderService
The proxy gets the first opportunity to execute logic before calling the actual method.
Step 3: TransactionInterceptor Starts the Transaction
The proxy delegates the work to Spring’s TransactionInterceptor.
This interceptor checks:
- Is the method transactional?
- Which propagation should be used?
- Which isolation level should be used?
- Should a new transaction be created?
If required, it asks the PlatformTransactionManager to begin a transaction.
Step 4: TransactionManager Opens a Database Transaction
Spring internally uses implementations such as:
- DataSourceTransactionManager
- JpaTransactionManager
The transaction manager obtains a database connection and executes:
connection.setAutoCommit(false);
This marks the beginning of the transaction.
Now all database operations will execute within the same transaction.
Step 5: Business Logic Executes
Your actual method finally runs.
@Transactional
public void placeOrder() {
orderRepository.save(order);
paymentRepository.save(payment);
cartRepository.clearCart(userId);
}
All repository calls use the same database connection.
Step 6: Commit or Rollback
If everything succeeds:
connection.commit();
If an exception occurs:
connection.rollback();
Finally, the connection is returned to the connection pool.
Why Does Spring Use ThreadLocal?
One common interview question is:
How do all repository methods use the same database connection?
Spring stores the transaction resources in a ThreadLocal using TransactionSynchronizationManager.
Thread 1
β
Connection A
---------------------
Thread 2
β
Connection B
Every repository call made within the same thread automatically uses the same connection.
Why Does Self-Invocation Fail?
Consider this code:
@Service
public class OrderService {
public void process() {
saveOrder();
}
@Transactional
public void saveOrder() {
}
}
Here,
process()
β
this.saveOrder()
The call never goes through the Spring Proxy.
Since the proxy is bypassed, Spring cannot start a transaction.
Therefore, @Transactional has no effect.
How to solve it?
Move the transactional method to another Spring bean or call it through the proxy.
Does @Transactional Work in a Monolith?
Yes.
In a monolithic application, all modules usually share the same database.
Example:
OrderService
β
βββ OrderRepository
βββ PaymentRepository
βββ CartRepository
Since every repository uses the same database, a single transaction can manage all operations.
This is the most common use of @Transactional.
Does @Transactional Work in Microservices?
Yesβbut only within a single microservice.
For example:
Order Service
β
βββ OrderRepository
βββ AuditRepository
Both repositories use the Order Service database.
@Transactional works perfectly here.
Can @Transactional Manage Transactions Across Multiple Microservices?
No.
Consider this architecture:
Order Service
β
βββ Order Database
β
βββ Calls
β
βΌ
Payment Service
β
βββ Payment Database
Now there are two separate databases and two independent transactions.
If the payment service fails after the order is saved, Spring cannot roll back the Order Service transaction because it only controls the current application’s database transaction.
This is one of the biggest limitations of @Transactional.
How Are Distributed Transactions Handled?
Instead of relying on @Transactional, modern microservices use patterns such as:
- Saga Pattern
- Eventual Consistency
- Outbox Pattern
- Kafka or RabbitMQ for event-driven communication
Each microservice commits its own transaction independently, and failures are handled using compensation logic rather than a single database rollback.
Common Interview Questions
1. Does @Transactional use AOP?
Yes. Spring uses AOP proxies to intercept method calls and apply transaction management.
2. What proxy does Spring create?
- JDK Dynamic Proxy (if an interface exists)
- CGLIB Proxy (if no interface exists)
3. What class actually manages the transaction?
PlatformTransactionManager
Common implementations:
- DataSourceTransactionManager
- JpaTransactionManager
4. What happens if an exception occurs?
By default:
- RuntimeException β Rollback
- Error β Rollback
- Checked Exception β Commit (unless configured using
rollbackFor)
5. Why doesn’t @Transactional work for self-invocation?
Because the method call bypasses the Spring proxy.
6. Can @Transactional work across multiple microservices?
No.
It only manages transactions within the current application’s database.
Distributed transactions require Saga, Eventual Consistency, or similar patterns.
Interview Answer (2-Minute Version)
“
@Transactionalworks internally using Spring AOP and the Proxy Pattern. When Spring detects a transactional method, it creates a proxy around the bean. Whenever the method is called, the proxy intercepts the request and delegates it toTransactionInterceptor, which asks thePlatformTransactionManagerto start a transaction by obtaining a database connection and disabling auto-commit. The business method then executes. If it completes successfully, Spring commits the transaction; otherwise, it rolls it back for runtime exceptions. Finally, the connection is released back to the connection pool. This works well in monolithic applications and within a single microservice, but it cannot manage transactions across multiple microservices or databases. For distributed transactions, patterns like Saga and Eventual Consistency are used.”
Key Takeaways
@Transactionaluses Spring AOP.- Spring creates a Proxy Object around the bean.
- The proxy invokes TransactionInterceptor.
PlatformTransactionManagerstarts and manages the database transaction.- All repository operations share the same connection through ThreadLocal.
- Success results in Commit; failures trigger Rollback.
- Self-invocation bypasses the proxy, so transactions are not applied.
@Transactionalis ideal for monolithic applications and single microservices.- For transactions spanning multiple services or databases, use Saga, Outbox Pattern, and Eventual Consistency instead of
@Transactional.