How does NOT_SUPPORTED differ from SUPPORTS and NEVER when a transaction is or isn't already active?
answer
- SUPPORTS joins, NEVER throws, NOT_SUPPORTED suspends
- Identical when no tx exists
- Only NOT_SUPPORTED touches (suspends) the caller's tx
- NEVER -> IllegalTransactionStateException
- None of the three starts a new tx
basics
~20 sSUPPORTS 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.
solid answer
~40 sAll three are "non-starting" propagations — none of them begins a new transaction. The difference is how they react to an already-active transaction. SUPPORTS is opportunistic: if a transaction is active it runs inside it, otherwise it runs non-transactionally — it never suspends. NEVER is a guard: if a transaction is active it throws IllegalTransactionStateException, otherwise it runs non-transactionally. NOT_SUPPORTED is the assertive one: regardless of the caller, it runs non-transactionally, and if a transaction happens to be active it suspends it (unbinding resources from the thread) and resumes it afterward. So when no transaction exists, all three behave identically — no transaction. The distinction only appears when a caller's transaction is present: SUPPORTS joins, NEVER fails, NOT_SUPPORTED suspends.
go deeper
Memorize the 3x2 table: no-tx vs active-tx for each mode.
Explain that the difference only appears with an active caller transaction.
Tie NOT_SUPPORTED's suspension to manager suspension support and resource unbinding.
Advise which mode to standardize on for a given service contract and why.
## The three "non-starting" propagations Spring's `Propagation` enum has three modes that never create a new transaction of their own: `SUPPORTS`, `NOT_SUPPORTED`, and `NEVER`. Comparing them is a classic interview probe because the behavior diverges *only* when a transaction is already active. | Propagation | No active tx | Active tx present | |---|---|---| | `SUPPORTS` | Runs non-transactionally | **Joins** the existing transaction (runs inside it) | | `NOT_SUPPORTED` | Runs non-transactionally | **Suspends** it, runs non-transactionally, resumes it | | `NEVER` | Runs non-transactionally | **Throws** `IllegalTransactionStateException` | ## SUPPORTS `SUPPORTS` means "use a transaction if one is already there, otherwise don't bother." It does **not** suspend and does **not** start anything. Subtle gotcha: with `SUPPORTS` and no active transaction, there is no well-defined transaction boundary, so the `readOnly` flag and isolation settings may not be reliably applied — behavior depends on the resource. It's a good fit for methods that can run either way. ## NOT_SUPPORTED `NOT_SUPPORTED` means "I want to run **without** a transaction, even if my caller has one." It actively suspends the caller's transaction using `AbstractPlatformTransactionManager.suspend(...)`, which unbinds the transactional `Connection`/`EntityManager` from the thread via `TransactionSynchronizationManager`, runs the body, then `resume(...)` re-binds. This is the only one of the three that touches the existing transaction. ## NEVER `NEVER` means "assert that no transaction is active." If one is, Spring throws `IllegalTransactionStateException` ("Existing transaction found for transaction marked with propagation 'never'"). It's a defensive contract for code that must never run inside a transaction. ## Why suspension matters for NOT_SUPPORTED but not the others SUPPORTS doesn't suspend because it's fine sharing the caller's transaction. NEVER doesn't suspend because it refuses to proceed at all. Only NOT_SUPPORTED both tolerates the caller's transaction *and* insists on running outside it — which forces an actual suspend/resume. That means NOT_SUPPORTED requires a transaction manager that supports suspension (`DataSourceTransactionManager`, `JpaTransactionManager`, `JtaTransactionManager` all do). ## Practical selection - Method that is agnostic and cheap → `SUPPORTS` (or just no annotation). - Method that must never accidentally be enrolled in a transaction → `NEVER`. - Method with a slow read you deliberately want *outside* the caller's transaction to release locks/connection → `NOT_SUPPORTED`.
- Which of the three requires transaction-manager suspension support and why?Only NOT_SUPPORTED, because it must actively suspend an existing transaction to run outside it. SUPPORTS joins and NEVER refuses, so neither needs suspend/resume.
- With SUPPORTS and no active transaction, is readOnly=true honored?Not reliably — without an actual transaction boundary there's nothing to apply the read-only optimization to, so the setting may be ignored. This is a known caveat of SUPPORTS.
saying these in an interview costs you the question
- Saying NEVER suspends the transaction (it throws instead)
- Saying SUPPORTS suspends the transaction (it joins, no suspension)
- Claiming all three behave differently when no transaction exists (they're identical then)