Understanding Transaction Isolation Levels and Propagation Behaviors in Spring
This article explains how to configure Spring transaction isolation levels and propagation behaviors, illustrates the effects of dirty read, non‑repeatable read, and phantom read with examples, and provides practical code solutions for handling rollback of failed sub‑tasks and self‑invocation issues.
The article begins with a question about rolling back only the sub‑tasks that fail during a batch operation and asks how to configure Spring transactions to achieve this behavior.
It then introduces transaction isolation as a key property that separates the visibility of data between concurrent transactions, describing the four standard isolation levels—READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, and SERIALIZABLE—along with their typical phenomena such as dirty reads, non‑repeatable reads, and phantom reads, illustrated with timeline tables.
To set an isolation level in a Spring project, the article shows a simple @Transactional annotation example:
@Transactional(isolation = Isolation.SERIALIZABLE)
public int insertUser(User user) {
return userDao.insertUser(user);
}It also provides the isolation‑level enum mapping used by Spring:
DEFAULT(-1), READ_UNCOMMITTED(1), READ_COMMITTED(2), REPEATABLE_READ(4), SERIALIZABLE(8);The discussion then moves to transaction propagation behaviors, explaining that Spring defines seven propagation types via the Propagation enum. The most commonly used are REQUIRED, REQUIRES_NEW, and NESTED, and the article includes the enum source code for reference.
public enum Propagation {
REQUIRED(0),
SUPPORTS(1),
MANDATORY(2),
REQUIRES_NEW(3),
NOT_SUPPORTED(4),
NEVER(5),
NESTED(6);
// ...
}It clarifies the difference between NESTED (which inherits the current transaction’s isolation and locks) and REQUIRES_NEW (which creates an independent transaction), noting that NESTED relies on database SAVEPOINT support.
Finally, the article addresses the common pitfall of @Transactional self‑invocation, explaining that internal method calls bypass Spring’s AOP proxy and therefore do not apply the configured isolation or propagation. Two solutions are offered: using separate service beans or retrieving the proxy from the Spring ApplicationContext, with a complete code example.
public class OrderServiceImpl implements OrderService, ApplicationContextAware {
private ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
@Transactional
public void methodA() {
OrderService orderService = applicationContext.getBean(OrderService.class);
for (int i = 0; i < 10; i++) {
orderService.methodB();
}
}
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public int methodB() {
// ...
return 0;
}
}The article concludes with a friendly sign‑off encouraging readers to like, share, and follow.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.