Common Scenarios Where Spring @Transactional Fails and How to Fix Them
This article outlines common situations that cause Spring @Transactional to fail—such as non‑public methods, internal method calls, unmanaged beans, non‑runtime exceptions, silent catches, incorrect propagation settings, and unsupported MySQL storage engines—and provides practical solutions to ensure transaction reliability.
In real‑world projects, developers often rely on Spring transactions to guarantee data consistency across multiple tables. However, various subtle mistakes can cause the @Transactional annotation to become ineffective, leading to data anomalies and wasted debugging time.
1. @Transactional on Non‑Public Methods
Spring creates proxies for beans, and only public methods are intercepted. If a protected, private, or package‑private method is annotated, the transaction settings are ignored. The fix is to keep the method public or enable AspectJ weaving.
2. Bean Not Managed by the Spring Container
If the class containing @Transactional is not a Spring bean (e.g., missing @Service), the annotation has no effect. Ensure the class is registered in the container.
@Service
public class StudentServiceImpl implements StudentService {
@Autowired
private StudentMapper studentMapper;
@Autowired
private ClassService classService;
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void insertClassByException(StudentDo studentDo) throws CustomException {
studentMapper.insertStudent(studentDo);
throw new CustomException();
}
}3. Internal Method Calls Bypass the Proxy
When a method in the same class calls another @Transactional method, the call is made directly (via this) and the proxy is bypassed, so the transaction does not start.
Solution: invoke the method through the current proxy.
public void insertClass(ClassDo classDo) throws CustomException {
// ((ClassServiceImpl)AopContext.currentProxy()).insertClassByException(classDo);
((ClassServiceImpl)AopContext.currentProxy()).insertClassByException(classDo);
}Also add @EnableAspectJAutoProxy(exposeProxy = true) to the configuration class.
4. Throwing Non‑RuntimeException
By default, Spring rolls back only on unchecked exceptions. Throwing a checked exception (e.g., Exception) will not trigger a rollback unless rollbackFor is specified.
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public void insertClassByException(ClassDo classDo) throws Exception {
classMapper.insertClass(classDo);
throw new Exception();
}5. Catching Exceptions Without Rethrowing
If a transactional method catches an exception and does not rethrow it (or throw a RuntimeException), the transaction will be committed despite the error.
try {
int i = 1 / 0;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(); // rethrow to trigger rollback
}6. Incorrect Propagation Setting
Using Propagation.NOT_SUPPORTED disables transaction support for the method, causing all database operations to run outside a transaction.
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void insertClassByException(ClassDo classDo) {
// operations will not be transactional
}7. MySQL Storage Engine Not Supporting Transactions
If the MySQL table uses the MyISAM engine, transactions are ignored because MyISAM does not support them. Switch to InnoDB (the default from MySQL 5.5 onward) to enable transactional behavior.
By addressing these seven pitfalls—ensuring public methods, proper bean registration, proxy‑based internal calls, appropriate exception handling, correct propagation, and a transactional‑compatible storage engine—developers can reliably use Spring transactions in backend applications.
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.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.
