Transactional annotation not working in Spring Boot
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
When @Transactional appears not to work in Spring Boot, the problem is usually not that Spring forgot how to start transactions. It is usually a proxy or configuration issue: the method is called the wrong way, the exception type does not trigger rollback, or the bean is not actually being managed through Spring’s transactional proxy.
@Transactional Works Through a Proxy
Spring transaction management is usually applied by wrapping your bean in a proxy. That proxy opens the transaction before the method call and commits or rolls back afterward.
That means the transaction advice only runs when the call goes through the Spring-managed proxy.
A normal working example:
This works when another bean calls orderService.placeOrder() through the Spring container.
Self-Invocation Is the Classic Trap
A very common failure case is calling a transactional method from another method in the same class.
This is called self-invocation. The call does not go through the proxy, so the transactional advice is skipped.
Typical fixes are:
- move the transactional method to another Spring-managed bean
- call the method through a proxied bean instead of
this - redesign the service boundary so the transactional entry point is external
Method Visibility Matters
Transactional methods are typically expected to be public in common proxy-based setups. If the method is private, Spring cannot usually apply the transactional advice the way developers expect.
Bad example:
Better:
Even when some proxy variants can handle more than public methods, public transactional boundaries are still the clearest and least surprising design.
Rollback Rules Surprise Many People
By default, Spring rolls back on unchecked exceptions such as RuntimeException, but not on every checked exception automatically.
This may not roll back the way you expect.
If you need rollback for checked exceptions, declare it explicitly:
This is one of the most common reasons developers think transactions are “not working” when they are actually being committed according to Spring’s default rules.
Make Sure the Bean Is Managed by Spring
If you instantiate the class manually with new, Spring cannot apply transactions.
Wrong:
Correct usage is dependency injection:
If the bean is not created by the container, the proxy does not exist.
Check the Transaction Manager and Persistence Setup
Spring Boot usually auto-configures transaction management correctly when you use standard data starters, but the transaction manager still has to match the persistence technology you are using.
If the application has multiple data sources or a nonstandard setup, verify:
- the correct transaction manager is present
- the repository or entity manager uses the same data source
- the transactional method is actually hitting the expected persistence context
These issues are less common than self-invocation, but they matter in more complex applications.
Common Pitfalls
The most common mistake is self-invocation, where a method inside the same class calls the transactional method directly and bypasses the proxy. Another is expecting rollback for checked exceptions without configuring rollbackFor. Developers also often put @Transactional on private methods or on classes they instantiate manually instead of letting Spring manage them. A final issue is assuming every data source and repository is automatically wired to the same transaction manager in multi-database setups.
Summary
- '
@Transactionalusually works through a Spring proxy, not by magic inside the class itself.' - Self-invocation is the most common reason transactional advice is skipped.
- Public transactional entry points are the safest design.
- By default, rollback behavior differs between unchecked and checked exceptions.
- Make sure the bean and the transaction manager are actually managed by Spring.
Related reading
- Transactional annotation works with saveAndFlush?
- transactional replication using script
- TransactionManagementError You can''t execute queries until the end of the ''atomic'' block while using signals, but only during Unit Testing
- Transactions between two replicating master mysql servers
- Transactional on Async methods in Spring
- Transactional Producer vs Just Idempotent Producer Java (Exception OutOfOrderSequenceException)
- Transactions in .net
- Transactions in spring boot testing not rolled back

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.