Keywords: Spring Transactions | Propagation Mechanism | REQUIRED | REQUIRES_NEW | Rollback Behavior | Performance Optimization
Abstract: This article provides an in-depth exploration of the core differences between PROPAGATION_REQUIRED and PROPAGATION_REQUIRES_NEW transaction propagation mechanisms in the Spring Framework. Through analysis of real-world multi-client concurrent scenarios, it details the key characteristics of both propagation types in terms of transaction independence, rollback behavior, and performance impact. The article explains how REQUIRES_NEW ensures complete transaction independence but may cause connection pool pressure, while REQUIRED maintains data consistency in shared transactions but requires attention to unexpected rollback risks. Finally, it offers selection advice based on actual performance metrics to avoid premature optimization pitfalls.
Fundamental Concepts of Transaction Propagation
In Spring Framework's transaction management, propagation mechanisms define how transactional methods behave within call chains. When multiple transactional methods call each other, propagation settings determine whether these methods share the same physical transaction or create independent transactions. Understanding propagation mechanisms is crucial for designing high-concurrency, highly reliable enterprise applications.
Deep Analysis of PROPAGATION_REQUIRED
@Transactional(propagation = Propagation.REQUIRED) is the default propagation behavior in Spring transactions. When a method is invoked, if a transaction already exists, the method joins that transaction; if no transaction exists, it creates a new one. This mechanism provides a good balance in most business scenarios.
From the perspective of physical transactions, REQUIRED propagation creates a physical database transaction when needed. Within the same call stack, all methods marked as REQUIRED typically share the same physical transaction. This means that database modifications by these methods are committed or rolled back within the same database transaction.
The logical transaction level is more refined. Each method marked as REQUIRED has its own logical transaction scope and can independently set rollback status. However, the key point is: when an inner logical transaction marks for rollback, the entire physical transaction is marked for rollback. This triggers an UnexpectedRollbackException, ensuring that the caller clearly knows the transaction was rolled back rather than committed.
Core Characteristics of PROPAGATION_REQUIRES_NEW
@Transactional(propagation = Propagation.REQUIRES_NEW) behaves fundamentally differently from REQUIRED. Regardless of whether a transaction currently exists, REQUIRES_NEW suspends any existing transaction (if present) and creates a completely new, independent transaction. This new transaction has its own database connection, isolation level settings, and timeout configuration.
In the code example:
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createUser(final UserBean userBean) {
// Database modification logic
}
Each time the createUser method is called, even if an outer transaction exists, Spring creates an independent transaction. This independence brings important advantages: rollback of each transaction does not affect other transactions. In multi-client concurrent scenarios, if the 100th client's operation fails, only that client's transaction rolls back, without affecting the first 99 successfully completed transactions.
Practical Impact in Multi-Client Scenarios
Consider a typical web application scenario: hundreds of clients simultaneously send requests to the server, each requiring database operations and returning clear transaction results (success or rollback). In such high-concurrency environments, the choice of propagation mechanism directly affects system reliability and performance.
When using REQUIRES_NEW, each client request creates an independent transaction. This ensures absolute transaction isolation—failure of one client's operation does not affect other clients. However, this independence comes at a cost: each independent transaction requires a separate database connection, which may quickly exhaust connection pool resources, especially when connection numbers are limited.
In contrast, REQUIRED propagation, when called from a non-transactional context (such as directly from a web controller), actually also creates a new transaction for each request. Transaction sharing only occurs when transactional methods call each other. Therefore, in multi-client scenarios, REQUIRED typically does not cause the problem of "one client failure causing all clients to roll back," because each request usually starts from a non-transactional context.
Performance vs. Correctness Trade-offs
Regarding performance concerns, premature optimization should be approached cautiously. REQUIRES_NEW may indeed increase system overhead because each transaction requires independent database connections and transaction management. However, in many scenarios, this overhead is acceptable, especially when data integrity and transaction independence are primary considerations.
The correct approach to performance optimization is: first ensure system correctness and data integrity, then identify real bottlenecks through actual performance testing. If testing shows that REQUIRES_NEW indeed causes unacceptable performance issues, then consider optimization strategies. Blindly choosing REQUIRED to avoid "potential" performance problems may introduce more serious data consistency issues.
Detailed Analysis of Rollback Behavior
Rollback mechanisms are key to understanding propagation behavior. In REQUIRES_NEW scenarios, exception handling has clear boundaries:
try {
userService.createUser(userBean); // REQUIRES_NEW propagation
} catch (Exception e) {
// Only the createUser method's transaction rolls back
// Outer transaction (if exists) is unaffected
}
Whether the exception propagates upward determines the fate of the outer transaction. If the exception is caught and not propagated further, the outer transaction can continue normally. If the exception propagates to the outer transaction boundary, the outer transaction will also roll back.
In REQUIRED propagation, rollback behavior is more complex. The rollback-only status set by inner methods affects the entire physical transaction. Even if outer methods attempt to commit, the transaction will ultimately roll back due to the inner rollback marker and throw an UnexpectedRollbackException.
Connection Pool and Deadlock Risks
An important risk of REQUIRES_NEW propagation is connection pool exhaustion and potential deadlocks. When multiple threads simultaneously hold outer transactions and attempt to create REQUIRES_NEW inner transactions, if the connection pool size is insufficient, threads may wait for each other for available connections, forming a deadlock.
Preventing this risk requires:
- Ensuring the database connection pool size is at least one more than the maximum concurrent threads
- Monitoring connection pool usage and setting reasonable timeout periods
- Using REQUIRES_NEW cautiously in high-pressure concurrent scenarios
Practical Selection Recommendations
Based on the above analysis, the following practical recommendations are provided:
When to choose REQUIRES_NEW:
- Absolute transaction independence is required; failure of one operation must not affect others
- Operations are logically independent business units
- The system has sufficient database connection resources
- Auxiliary operations like audit logging, message sending
When to choose REQUIRED:
- Multiple operations need atomic commit or rollback
- Operations belong to the same logical work unit in business logic
- Connection resources are limited and need optimization
- Most business service methods
Most importantly, the choice of propagation mechanism should be based on business requirements rather than performance guesses. Through actual performance testing and monitoring, making data-driven decisions ensures optimal performance while maintaining system correctness.