skip to content

NOT_SUPPORTED

NOT_SUPPORTED suspends any active transaction, runs the method without one, and resumes afterwards — useful for a long reporting query that should not hold locks. Interviewers ask it to check you know suspension is a real cost, not a free annotation.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

4

What does Propagation.NOT_SUPPORTED do in Spring's declarative transaction management?

level: juniorimportance: must knowfreq 45%

answer

  1. Suspend outer tx, run non-transactionally, resume
  2. Same suspend/resume machinery as REQUIRES_NEW but starts nothing
  3. Long read-only / reporting calls
  4. Not atomic with caller
  5. Proxy self-invocation still applies

basics

~10 s

NOT_SUPPORTED runs the method without a transaction. If a transaction is already active, Spring pauses (suspends) it, runs the method non-transactionally, then resumes the paused transaction afterward.

solid answer

~40 s

NOT_SUPPORTED is a propagation mode you set via @Transactional(propagation = Propagation.NOT_SUPPORTED). It means "execute non-transactionally." If no transaction exists, the method just runs without one. If a caller already started a transaction, Spring suspends that transaction for the duration of the call, runs the method with no active transaction bound to the thread, then resumes the outer transaction when the method returns. It is typically used for long read-only or reporting queries where you do not want to hold a database transaction (and its locks/connection) open. Because there is no transaction inside, a failure inside won't roll back the outer transaction, and the outer rollback won't undo work done here.

code

java · 15 lines
java
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ReportService {

    // Runs with NO active transaction. If the caller had one,
    // it is suspended for the duration of this method and resumed after.
    @Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
    public Report buildHeavyReport(long tenantId) {
        // Long-running aggregation query -- we intentionally do not
        // hold the caller's transaction (and its locks) open here.
        return reportDao.aggregate(tenantId);
    }
}

go deeper

for a junior

Know the one-line behavior: suspend the current transaction, run without one, resume.

for a middle

Contrast with SUPPORTS and NEVER; know it isn't atomic with the caller.

for a senior

Explain suspend/resume via AbstractPlatformTransactionManager and the visibility/connection implications.

for a principal

Reason about when suspending a slow read is worth it vs. connection-pool and consistency trade-offs.

## What propagation means In Spring, **propagation** controls what happens to transactions when one `@Transactional` method calls another. Spring's `Propagation` enum (in `org.springframework.transaction.annotation`) has seven values: `REQUIRED` (default), `REQUIRES_NEW`, `NESTED`, `SUPPORTS`, `NOT_SUPPORTED`, `MANDATORY`, and `NEVER`. ## NOT_SUPPORTED specifically `Propagation.NOT_SUPPORTED` means: **run this method with no transaction active on the thread.** Two cases: - **No active transaction on entry:** the method simply runs non-transactionally. Same effective behavior as if there were no `@Transactional` at all. - **A transaction is already active (started by a caller):** Spring **suspends** that transaction — it unbinds the transactional resources (e.g. the JDBC `Connection`) from the current thread via `TransactionSynchronizationManager` — executes your method with nothing bound, then **resumes** the suspended transaction after your method returns (or throws). ## The mechanism under the hood The orchestration lives in `AbstractPlatformTransactionManager`. When a `NOT_SUPPORTED` boundary is entered while a transaction exists, the manager calls its internal `suspend(...)`, which captures a `SuspendedResourcesHolder` (the unbound connection, synchronizations, isolation info, read-only flag, name). After the method body completes, `resume(...)` re-binds those resources to the thread. This is the same suspend/resume machinery `REQUIRES_NEW` uses — the difference is `REQUIRES_NEW` starts a *new* transaction after suspending, while `NOT_SUPPORTED` starts *nothing*. ## Consequences you must understand - **Not atomic with the caller:** work done inside NOT_SUPPORTED is not part of the outer transaction. If the outer transaction later rolls back, anything the NOT_SUPPORTED method already did is *not* undone (it was never in that transaction). - **Separate connection / visibility:** inside NOT_SUPPORTED, database reads run outside the outer transaction. They typically use a fresh connection obtained per statement (auto-commit mode via the `DataSource`), so they will **not** see the outer transaction's uncommitted changes. - **Requires a manager that supports suspension:** `DataSourceTransactionManager`, `JpaTransactionManager`, and `JtaTransactionManager` all support suspend/resume. A manager that cannot suspend throws `TransactionSuspensionNotSupportedException` if asked to. ## When to use it The canonical use case is a **long-running read-only or reporting query** invoked from within a broader transaction, where you deliberately do *not* want to keep the outer transaction (and its locks and pinned connection) open while the slow read runs. ## Gotchas - **Proxy self-invocation:** like all `@Transactional` propagation, NOT_SUPPORTED only takes effect when the call goes through the Spring proxy. Calling the method from within the same bean (`this.method()`) bypasses the proxy, so no suspension happens. - **Confusing it with NEVER:** `NEVER` *throws* if a transaction exists; `NOT_SUPPORTED` *suspends and continues*. `SUPPORTS` runs in the existing transaction if there is one but does not start a new one — it does not suspend.

  • How is NOT_SUPPORTED different from REQUIRES_NEW?
    Both suspend an existing transaction, but REQUIRES_NEW then starts a brand-new independent transaction (committed/rolled back on its own), while NOT_SUPPORTED starts no transaction at all and runs non-transactionally.
  • If the NOT_SUPPORTED method throws, does the outer transaction roll back?
    Not because of the suspension itself — the exception simply propagates. Whether the outer transaction rolls back depends on how the caller handles the propagated exception, per the caller's own rollback rules. The inner method had no transaction to roll back.

saying these in an interview costs you the question

  • Saying NOT_SUPPORTED starts a new transaction (that's REQUIRES_NEW)
  • Saying it throws when a transaction exists (that's NEVER)
  • Assuming inner reads see the outer transaction's uncommitted writes

context

open as a page

How does NOT_SUPPORTED differ from SUPPORTS and NEVER when a transaction is or isn't already active?

level: middleimportance: should knowfreq 38%

basics

~20 s

SUPPORTS joins an existing transaction but starts none if there isn't one. NEVER throws if a transaction exists, else runs without one. NOT_SUPPORTED always runs without one — suspending any existing transaction rather than joining or failing.

open as a page

Explain the suspend/resume mechanism behind NOT_SUPPORTED and its effect on data visibility and connections.

level: seniorimportance: should knowfreq 30%

basics

~20 s

Spring's transaction manager unbinds the active connection from the thread (suspend), runs the method with a fresh non-transactional connection, then rebinds the original (resume). Reads inside can't see the outer transaction's uncommitted changes because they use a different connection.

open as a page

When would you choose NOT_SUPPORTED for a reporting call, and what design trade-offs and pitfalls must you weigh?

level: principalimportance: nice to knowfreq 18%

basics

~10 s

Use NOT_SUPPORTED for a long read-only/reporting query called from within a transaction, so you don't hold the caller's transaction, locks, and connection open. Weigh connection-pool doubling, lost read-your-writes visibility, and proxy self-invocation.

open as a page