skip to content

What does Propagation.REQUIRES_NEW do in Spring's @Transactional?

level: juniorimportance: must knowfreq 72%

answer

  1. Always new tx, suspend the outer
  2. Separate Connection per tx
  3. Two connections in pool at once
  4. Commits independently of caller
  5. Self-invocation bypasses proxy

basics

~10 s

REQUIRES_NEW always starts a brand-new, independent transaction. If a transaction is already running, Spring pauses (suspends) it, runs the new one on its own database connection, then resumes the old one.

solid answer

~40 s

Propagation.REQUIRES_NEW tells Spring's transaction manager to always run the method in its own new transaction. If a caller already has an active transaction, that outer transaction is suspended (its resources, like the JDBC Connection, are unbound from the thread) and a second, independent inner transaction runs on a separate Connection. The inner transaction commits or rolls back entirely on its own, regardless of the outer one; when it finishes, the outer transaction is resumed. This contrasts with the default REQUIRED, which joins an existing transaction. Use REQUIRES_NEW when a unit of work must be durable independently of the caller — the classic example is writing an audit or log record that must persist even if the surrounding business transaction later rolls back.

code

java · 28 lines
java
@Service
public class OrderService {
    private final AuditService auditService; // injected bean = proxied
    private final OrderRepository orders;

    public OrderService(AuditService auditService, OrderRepository orders) {
        this.auditService = auditService;
        this.orders = orders;
    }

    @Transactional // REQUIRED (default) — the outer business tx
    public void placeOrder(Order order) {
        orders.save(order);
        // Runs in its OWN new tx; commits even if placeOrder later throws
        auditService.record("order attempt: " + order.getId());
        if (order.getTotal() < 0) {
            throw new IllegalStateException("bad order"); // outer rolls back...
        }                                                 // ...but audit row stays
    }
}

@Service
class AuditService {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void record(String message) {
        // separate connection, independent commit
    }
}

go deeper

for a junior

Should know it always starts a new independent transaction and the audit-log use case.

for a middle

Should explain suspension, the second connection, and independent commit/rollback.

for a senior

Should raise the self-invocation proxy gotcha and connection-pool pressure.

for a principal

Should reason about pool sizing/deadlock risk and contrast with NESTED and distributed-tx implications.

## What a transaction is A database transaction is a group of operations that either all succeed (commit) or all undo (rollback), giving atomicity. In Spring you mark a method with `@Transactional` and Spring opens a transaction before the method and commits/rolls back after it, using a `PlatformTransactionManager` (e.g. `DataSourceTransactionManager` for JDBC/JPA). ## Propagation **Propagation** decides what happens when a `@Transactional` method is called while another transaction is *already* in progress on the same thread. The default is `Propagation.REQUIRED`: join the existing transaction if there is one, otherwise start a new one. ## What REQUIRES_NEW does `Propagation.REQUIRES_NEW` means: *always* run in a fresh, independent transaction. - If **no** transaction exists, it simply starts one (behaving like REQUIRED in that case). - If a transaction **already exists**, Spring **suspends** the current (outer) transaction and starts a **new inner** transaction. **Suspension** means Spring unbinds the outer transaction's resources from the current thread. Concretely, the outer JDBC `Connection` (held in a `ConnectionHolder` bound to the thread via `TransactionSynchronizationManager`) is set aside. A **second, separate `Connection`** is obtained from the `DataSource` for the inner transaction. So at that moment two physical connections are checked out from the pool at once. The inner transaction runs to its own commit or rollback, completely independent of the outer one. After it finishes, Spring **resumes** the outer transaction by re-binding its `Connection` to the thread, and the outer method continues. ## Independence — the key property Because they use different connections, the two transactions are isolated at the DB level: - The inner transaction can **commit even if the outer later rolls back** — that committed data stays. - The inner transaction can **roll back without affecting** the outer one (the outer just sees the called method threw, and can catch it). - The outer transaction typically **cannot see** the inner transaction's uncommitted changes while it is running (they are on different connections), and vice-versa — this can cause surprising read behavior. ## When to use it - **Audit / logging / event records** that must survive even if business logic rolls back. - Sending a record to an outbox, incrementing a counter, or recording a failed-attempt marker that must persist. - Any sub-operation whose durability must be decoupled from the caller's outcome. ## Key gotchas 1. **Self-invocation doesn't work.** `@Transactional` is applied by a Spring AOP proxy. Calling a REQUIRES_NEW method from *another method in the same class* bypasses the proxy, so no new transaction starts. You must call it through an injected bean (the proxy). 2. **Two connections at once** — under load this doubles connection demand and can **exhaust the connection pool / deadlock** if the pool is small (outer holds one, waits for inner to get a second). 3. **Not a nested/savepoint transaction.** REQUIRES_NEW is a fully independent physical transaction; `Propagation.NESTED` (savepoints on the *same* connection) is the different thing people confuse it with. 4. **Requires suspend support.** The transaction manager must support suspension (the standard `DataSourceTransactionManager`/`JpaTransactionManager` do).

  • Why does calling the REQUIRES_NEW method from within the same class fail to start a new transaction?
    @Transactional is enforced by an AOP proxy that wraps the bean. A self-call (this.method()) goes straight to the target instance, bypassing the proxy, so no transaction advice runs. You must call it through an injected reference to the (proxied) bean.
  • How does REQUIRES_NEW differ from the default REQUIRED?
    REQUIRED joins an existing transaction if one is active (single connection, shared commit/rollback). REQUIRES_NEW always creates an independent transaction on a separate connection, suspending any existing one, and commits/rolls back on its own.

saying these in an interview costs you the question

  • Saying REQUIRES_NEW just 'continues' or reuses the current transaction
  • Thinking it uses the same connection as the outer transaction
  • Believing a self-call inside the same class will trigger the new transaction
  • Confusing it with NESTED (savepoints)

context