skip to content

Compare Propagation.NESTED and Propagation.REQUIRES_NEW. When would you choose one over the other?

level: middleimportance: must knowfreq 60%

answer

  1. REQUIRES_NEW = 2 tx, independent commit
  2. NESTED = 1 tx + savepoint
  3. outer rollback: NESTED loses, REQUIRES_NEW keeps
  4. REQUIRES_NEW = 2 connections => pool risk
  5. audit log => REQUIRES_NEW; skip bad row => NESTED

basics

~20 s

REQUIRES_NEW opens a separate transaction that commits on its own, surviving an outer rollback. NESTED stays inside one transaction using a savepoint; nested work is lost if the outer rolls back. Use REQUIRES_NEW for truly independent commits, NESTED for partial rollback within one unit.

solid answer

~50 s

REQUIRES_NEW suspends the outer transaction and opens a genuinely separate physical transaction, typically with its own connection, that commits or rolls back independently. Its committed work survives even if the outer later rolls back — good for audit logs or outbox rows you want persisted regardless. NESTED uses a JDBC savepoint inside the single existing physical transaction: the inner block can be rolled back to that savepoint without aborting the outer, but because it is still one transaction, an outer rollback discards the nested work too and both commit atomically at the end. Choose REQUIRES_NEW when the inner work must persist independently; choose NESTED when you want a skip-and-continue partial rollback while keeping everything atomic as a whole. Note REQUIRES_NEW ties up two connections simultaneously (deadlock risk under a small pool), and NESTED needs a savepoint-capable manager like DataSourceTransactionManager.

code

java · 11 lines
java
// REQUIRES_NEW: audit must persist even if order fails
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void writeAudit(AuditEvent e) {
    auditRepo.save(e); // commits independently
}

// NESTED: skip a bad line item but keep the order atomic overall
@Transactional(propagation = Propagation.NESTED)
public void addLineItem(LineItem item) {
    lineItemRepo.save(item); // rolls back to savepoint if it throws
}

go deeper

for a junior

Grasp the headline: REQUIRES_NEW = independent commit; NESTED = savepoint inside one transaction.

for a middle

Must state the directional survival difference and give one correct use case for each.

for a senior

Should raise connection-pool/deadlock cost of REQUIRES_NEW and manager-support constraint of NESTED.

for a principal

Should reason about isolation/visibility, pool sizing, and when neither fits (prefer idempotent retries, outbox pattern, or eventual consistency).

## The two mechanisms **REQUIRES_NEW** (`Propagation.REQUIRES_NEW`): Spring **suspends** the currently running transaction (holds its resources aside) and starts a **brand-new physical transaction**. This new transaction usually acquires its **own database connection** from the pool. It commits or rolls back **entirely on its own**. When it finishes, the outer transaction is **resumed**. Key consequence: whatever the inner transaction committed is durable *immediately and independently* — if the outer transaction later rolls back, the inner's committed changes **remain**. **NESTED** (`Propagation.NESTED`): Spring does not start a new physical transaction. It calls `Connection.setSavepoint()` on the **same connection** already used by the outer transaction. The inner work runs within the outer physical transaction. On inner failure Spring calls `rollback(savepoint)` — undoing only inner changes — and the outer continues. On success the savepoint is released. Everything still commits together at the outer boundary, so an **outer rollback undoes the nested work as well**. ## Directionality of protection (the crux) - NESTED protects the **outer** from the **inner's** failure (partial rollback), but does NOT protect the inner from the outer's failure. - REQUIRES_NEW makes the inner **fully independent** in both directions: its commit survives outer rollback, and its rollback doesn't touch the outer. ## When to use which **Use REQUIRES_NEW when the inner work must persist no matter what the outer does:** - Writing an audit/log record that should survive even if the business transaction fails. - Sending-related bookkeeping, allocating a sequence/number, incrementing a counter that must stick. **Use NESTED when you want partial rollback but still one atomic unit:** - Batch processing where a single bad item should be skipped (roll back that item) while the whole batch commits or aborts together. - Trying an optional sub-operation that may fail and should be cleanly undone without killing the parent, yet must NOT survive if the parent aborts. ## Practical constraints and gotchas - **Connections/pool**: REQUIRES_NEW holds the suspended outer connection AND the new inner connection at the same time. Deeply nested or looped REQUIRES_NEW can exhaust a small pool and even self-deadlock (all connections held, none available). NESTED reuses one connection, so no extra connection pressure. - **Transaction manager support**: NESTED requires a `PlatformTransactionManager` supporting savepoints — `DataSourceTransactionManager` / `JdbcTransactionManager` do; `JpaTransactionManager` and `JtaTransactionManager` do **not** by default (throwing `NestedTransactionNotSupportedException`). REQUIRES_NEW works with all standard managers. - **Isolation/visibility**: With REQUIRES_NEW the inner transaction is separate, so it cannot see the outer's uncommitted changes (subject to isolation level). With NESTED the inner sees everything the outer has done so far because it is the same transaction. - **Self-invocation**: both rely on proxy-based AOP; an in-class call bypasses the propagation entirely. - **Rollback rules still apply**: only exceptions that Spring treats as rollback-triggering (by default unchecked/Error) cause the rollback; catching the exception before the boundary changes behavior. ## Summary table | | NESTED | REQUIRES_NEW | |---|---|---| | Physical transactions | 1 | 2 | | Connections used | 1 (shared) | 2 (outer suspended) | | Inner commit survives outer rollback? | No | Yes | | Partial rollback of inner only? | Yes (savepoint) | Yes (separate tx) | | Manager support | savepoint-capable only | all | | Pool pressure | low | higher |

  • Why can REQUIRES_NEW cause a connection-pool deadlock while NESTED cannot?
    REQUIRES_NEW keeps the suspended outer connection open while also grabbing a new one for the inner transaction, so it consumes an extra connection per level; enough concurrent/nested calls can hold every pooled connection with none free to grant, deadlocking. NESTED reuses the single existing connection via a savepoint, so it adds no connection demand.
  • If the inner method must survive an outer rollback, which do you pick and why?
    REQUIRES_NEW — it commits in a separate physical transaction, so its result is durable independently of the outer. NESTED would lose the work because it is part of the same physical transaction that the outer rollback undoes.

saying these in an interview costs you the question

  • Saying NESTED and REQUIRES_NEW are basically the same
  • Claiming NESTED opens a new connection / new physical transaction
  • Thinking REQUIRES_NEW's inner tx is undone by an outer rollback
  • Ignoring that REQUIRES_NEW consumes two connections at once

context