What does NEVER propagation guarantee, and how does it differ from NOT_SUPPORTED?
answer
- NEVER = must have NO tx, else throw
- NOT_SUPPORTED = run outside tx, suspend if present
- NEVER throws vs NOT_SUPPORTED suspends
- NEVER is the mirror of MANDATORY
- both run non-transactionally
basics
~10 sNEVER guarantees the method runs with no active transaction, throwing IllegalTransactionStateException if one exists. NOT_SUPPORTED also runs non-transactionally but tolerates an existing transaction by suspending it instead of throwing.
solid answer
~50 sNEVER is a guard: the method must not execute inside a transaction. If none is active it runs normally (non-transactionally); if a transaction is active the interceptor throws org.springframework.transaction.IllegalTransactionStateException ('Existing transaction found for transaction marked with propagation never'). NOT_SUPPORTED has the same end state — code runs without a transaction — but it is permissive: when a transaction is active it suspends it, runs the body outside it, then resumes it afterward. So NEVER is an assertion that fails loudly, while NOT_SUPPORTED is an accommodation that silently sidesteps. Use NEVER to catch a design violation (this code must never be in a tx); use NOT_SUPPORTED when you legitimately want to escape an ambient transaction, e.g. for a long-running read or a call you don't want holding a DB connection/lock. Both require the transaction manager to support suspension for the NOT_SUPPORTED case.
code
java · 12 lines@Service
public class ExternalOps {
// Must NOT be inside a tx: throws if a caller opened one.
@Transactional(propagation = Propagation.NEVER)
public void strictNonTxCall() { externalSystem.push(); }
// Tolerant: if a tx is active it is suspended, this runs
// outside it, then the tx resumes afterward.
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public Report longRunningReport() { return reportDao.build(); }
}go deeper
Know NEVER throws if a transaction is active.
State that both run non-transactionally and that NEVER throws while NOT_SUPPORTED suspends.
Explain suspend/resume mechanics and pick the right one for escaping an ambient transaction.
Reason about lock/connection-holding tradeoffs and when strict NEVER guards belong in an architecture vs pragmatic NOT_SUPPORTED escapes.
**NEVER** = `@Transactional(propagation = Propagation.NEVER)`. It asserts the **absence** of a transaction. - No active transaction → method runs non-transactionally (the intended path). - Active transaction → interceptor throws `org.springframework.transaction.IllegalTransactionStateException` (*"Existing transaction found for transaction marked with propagation 'never'"*). The body does not run. NEVER never suspends anything — it only validates. It is symmetric to MANDATORY: MANDATORY demands a transaction, NEVER forbids one. **NOT_SUPPORTED** = `Propagation.NOT_SUPPORTED`. It also results in the body running **non-transactionally**, but it is tolerant: - No active transaction → runs non-transactionally. - Active transaction → **suspends** it (via `PlatformTransactionManager` / `TransactionSynchronizationManager`), runs the body outside any transaction, then **resumes** the suspended transaction when the method returns. **Key difference:** presence of an ambient transaction. NEVER treats it as an error and aborts; NOT_SUPPORTED treats it as something to step around and continues. Choosing between them is about intent: - Use **NEVER** when running inside a transaction would be a *bug* you want surfaced immediately — a strict contract that this operation must always be outside transactional scope. - Use **NOT_SUPPORTED** when you *expect* callers may be transactional but this particular work should not participate — e.g. a long-running report query you don't want holding write locks, calling a slow external service you don't want prolonging a DB transaction, or bulk operations you want auto-committed independently. **Mechanism & caveats:** - Both rely on the thread-bound transaction state and the AOP proxy; **self-invocation bypasses** them. - NOT_SUPPORTED requires the transaction manager to support suspend/resume (JpaTransactionManager and DataSourceTransactionManager do). - With NEVER (or NOT_SUPPORTED) running non-transactionally, there is no rollback semantics and isolation is the connection default — don't rely on `@Transactional` guarantees inside such a method. - A frequent mistake: expecting NEVER to 'suspend' the transaction like NOT_SUPPORTED. It does not; it throws.
- If you want to run a slow external call from inside a transactional service without holding the DB transaction open, which propagation fits — NEVER or NOT_SUPPORTED?NOT_SUPPORTED — it suspends the active transaction, runs the call outside it, and resumes afterward. NEVER would throw because a transaction is active.
saying these in an interview costs you the question
- Saying NEVER suspends the existing transaction (that's NOT_SUPPORTED)
- Saying NOT_SUPPORTED throws when a transaction exists
- Thinking NEVER starts a transaction