Spring Transaction Propagation Behaviors: Practical Limits in Spring 6 / Boot 3
1. Propagation Behaviors
- REQUIRED: Joins an existing transaction if one is available; otherwise, creates a new one.
- REQUIRES_NEW: Suspends the outer transaction and creates an independent transaction, requiring an additional connection.
- SUPPORTS: Joins an existing transaction if one is available; otherwise, runs without a transaction.
- NOT_SUPPORTED: Suspends any existing transaction and runs without one.
- MANDATORY: Requires an existing transaction.
- NEVER: Fails if a transaction already exists.
- NESTED: Creates a nested boundary within a transaction that supports savepoints.
2. Example
JAVA
@Service
public class OrderService {
@Transactional(rollbackFor = Exception.class)
public void create(Order order) {
repository.insert(order);
auditService.record(order.id());
}
}
@Service
public class AuditService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void record(long id) {
// 独立提交审计事务
}
}
3. When Transactions Don't Work
Declarative transactions rely on a proxy, so this.innerMethod() may bypass the proxy. Other causes include a bean created with new, a caught exception, a checked exception without rollbackFor configured, a call running on another thread, a database that doesn't support transactions, or the wrong transaction manager. Prefer splitting the bean into separate components so calls go through the proxy.
4. System Boundaries
NESTED usually relies on the same physical transaction and a savepoint, whereas REQUIRES_NEW uses a separate physical transaction. Spring local transactions don't automatically propagate across threads, MQ, HTTP, or RPC. For cross-service operations, use reliable messaging, compensation, TCC, or Seata.