Why @Transactional Might Fail in Spring and How to Fix It
This article explains common reasons why Spring's @Transactional annotation can become ineffective—such as self‑invocation, non‑public methods, multiple data sources, incorrect rollback settings, and unsupported database engines—and provides concrete code examples and solutions to ensure proper transaction management.
1. Self‑invocation within the same class
When a method annotated with @Transactional is called from another method of the same class, Spring AOP cannot create a proxy, so the transaction is not applied.
public class A {
public void methodA() {
methodB();
// other operations
}
@Transactional
public void methodB() {
// write to database
}
}Solution: Move the transactional method to a separate bean so that Spring can proxy it.
@Service
@AllArgsConstructor
public class A {
private B b;
public void methodA() {
b.methodB();
// other operations
}
}
@Service
public class B {
@Transactional
public void methodB() {
// write to database
}
}2. @Transactional on a non‑public method
Spring AOP only intercepts public methods. If the annotated method has private, protected, or package‑private visibility, the transaction will not be started.
public class TransactionalMistake {
@Transactional
private void method() {
// write to database
}
}Fix: Change the method visibility to public.
3. Multiple data sources
When a single operation writes to two different data sources, the default transaction manager cannot span them, so the transaction will not roll back.
public class TransactionalMistake {
@Transactional
public void createOrder(Order order) {
orderRepo1.save(order);
orderRepo2.save(order);
}
}Use a JTA transaction manager to coordinate transactions across multiple databases.
4. Incorrect rollback exception configuration
By default Spring rolls back only for RuntimeException and Error. Checked exceptions do not trigger a rollback unless configured.
Define custom exceptions as subclasses of RuntimeException or specify rollbackFor on the annotation.
@Transactional(rollbackFor = XXXException.class)
public void method() throws XXXException {
// ...
}5. Database engine does not support transactions
If the underlying tables use a storage engine without transaction support (e.g., MyISAM), the transaction will never roll back.
Ensure the dialect is set to an engine that supports transactions, such as InnoDB for MySQL:
spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialectCheck the created tables to confirm they use InnoDB.
Conclusion
These are the most common pitfalls that cause @Transactional to be ineffective. If you encounter other scenarios, feel free to share them so the article can be updated for future readers.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
