Mastering Spring Transaction Propagation: When and How Transactions Merge, Suspend, or Nest
This article explains the seven Spring transaction propagation levels, shows how nested @Transactional methods interact under each level, and provides concrete code‑level examples that illustrate when transactions are merged, suspended, started anew, or rolled back, helping developers choose the right strategy for reliable enterprise applications.
What is Spring Transaction Propagation
In a Spring application, transaction propagation defines how a transactional method behaves when it is called from another transactional method. The propagation level determines whether the inner method joins the existing transaction, starts a new one, runs without a transaction, or throws an exception.
Propagation Levels Defined by Spring
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS
PROPAGATION_MANDATORY
PROPAGATION_REQUIRES_NEW
PROPAGATION_NOT_SUPPORTED
PROPAGATION_NEVER
PROPAGATION_NESTED
The article walks through each level, explains the underlying rules, and shows when each should be used.
How Each Propagation Works
1. REQUIRED (default)
If a transaction already exists, the method joins it; otherwise a new transaction is created.
Example (TestAService and TestBService):
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { /* insert A */ testBService.methodB(); }
@Transactional(propagation = Propagation.REQUIRED)
public void methodB() { /* insert B */ }Caller does not start a transaction → methodA opens Transaction‑1.
methodB joins Transaction‑1 because its propagation is REQUIRED.
Both inserts are executed within the same transaction and are committed together, or both are rolled back if any exception occurs.
2. REQUIRES_NEW
Always starts a new transaction, suspending any existing one.
Example:
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { /* insert A */ testBService.methodB(); }
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() { /* insert B */ }methodA opens Transaction‑1.
When methodB is invoked, Transaction‑1 is suspended and Transaction‑2 is created for methodB.
Transaction‑2 commits independently; after it finishes, Transaction‑1 resumes and later commits.
If methodB throws an exception, only Transaction‑2 rolls back; Transaction‑1 can still commit provided methodA catches the exception.
3. SUPPORTS
If a transaction exists, the method joins it; otherwise it runs without a transaction.
Scenario 1 – outer method has no transaction:
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() { /* insert B */ }methodA (non‑transactional) calls methodB.
Because there is no surrounding transaction, methodB also executes non‑transactionally.
Scenario 2 – outer method is REQUIRED:
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { /* insert A */ testBService.methodB(); }
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() { /* insert B */ }methodA opens Transaction‑1.
methodB joins Transaction‑1 because a transaction is already present.
Both inserts are committed together.
4. NOT_SUPPORTED
Suspends any existing transaction and executes the method non‑transactionally.
Example:
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { /* insert A */ testBService.methodB(); }
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodB() { /* insert B */ }methodA opens Transaction‑1.
When methodB is called, Transaction‑1 is suspended; methodB runs without a transaction.
After methodB finishes, Transaction‑1 resumes and later commits.
5. NEVER
Method must not run inside a transaction; if a transaction exists, an exception is thrown.
Example:
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { /* insert A */ testBService.methodB(); }
@Transactional(propagation = Propagation.NEVER)
public void methodB() { /* insert B */ }methodA opens Transaction‑1.
Calling methodB triggers an exception because its propagation is NEVER.
Transaction‑1 is rolled back as a result of the exception.
6. MANDATORY
Method must run inside an existing transaction; otherwise an exception is thrown.
Example when no outer transaction exists:
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() { /* insert B */ }Calling methodB without a surrounding transaction causes an exception.
Example when an outer transaction exists (REQUIRED):
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { /* insert A */ testBService.methodB(); }
@Transactional(propagation = Propagation.MANDATORY)
public void methodB() { /* insert B */ }methodA opens Transaction‑1.
methodB joins Transaction‑1 because a transaction is already present.
Both operations are committed together.
7. NESTED
Creates a savepoint within the existing transaction. If the nested method rolls back, only the work after the savepoint is undone.
Example:
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() { /* insert A */ testBService.methodB(); }
@Transactional(propagation = Propagation.NESTED)
public void methodB() { /* insert B */ }methodA opens Transaction‑1 (or joins an existing one).
methodB creates a savepoint inside Transaction‑1.
If methodB throws an exception, only the changes after the savepoint are rolled back; methodA can still commit.
Summary
The article clarifies how Spring’s seven transaction propagation options affect nested @Transactional calls, demonstrates each behavior with concrete code snippets and execution flow diagrams, and explains the impact on commit and rollback semantics. Understanding these rules enables developers to design reliable, atomic business operations in enterprise‑level Java back‑end systems.
Author: Zhou Shaobin (source: vivo互联网技术)
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.
Architect
Professional architect sharing high‑quality architecture insights. Topics include high‑availability, high‑performance, high‑stability architectures, big data, machine learning, Java, system and distributed architecture, AI, and practical large‑scale architecture case studies. Open to ideas‑driven architects who enjoy sharing and learning.
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.
