What is Propagation.REQUIRED in Spring's @Transactional, and how does it decide whether to start a new transaction?
answer
- Default propagation
- Join if exists, else start new
- One physical tx, one Connection
- Atomic across service methods
- Thread-bound Connection
basics
~10 sREQUIRED is the default propagation. If a transaction is already running, the method joins it; if none exists, Spring starts a new one. So the code always runs inside exactly one transaction.
solid answer
~40 sPropagation.REQUIRED is the default value of @Transactional. Its rule is simple: support a current transaction if one exists, otherwise create a new one. When an outer @Transactional method calls an inner @Transactional(REQUIRED) method, the inner call joins the outer's transaction instead of opening a second one — they share a single physical transaction and the same database Connection. This means both methods commit or roll back together as a unit. Because it's the default, most Spring service methods use REQUIRED without stating it explicitly. You reach for other propagations (REQUIRES_NEW, NESTED, SUPPORTS) only when you need behavior different from 'always run in one shared transaction.'
code
java · 23 lines@Service
public class OrderService {
private final InventoryService inventory;
OrderService(InventoryService inventory) { this.inventory = inventory; }
// REQUIRED is the default — no transaction active yet, so a new one starts here
@Transactional
public void placeOrder(Order order) {
saveOrder(order);
inventory.reserve(order); // joins THIS transaction, no new Connection
}
}
@Service
public class InventoryService {
@Transactional // == @Transactional(propagation = Propagation.REQUIRED)
public void reserve(Order order) {
// runs on the same physical transaction/Connection as placeOrder
}
}go deeper
Know it's the default and the 'join or start' rule.
Explain the shared physical transaction and single Connection across nested calls.
Connect REQUIRED to atomicity guarantees and contrast with REQUIRES_NEW/NESTED.
Frame REQUIRED as the default that shapes transaction boundaries and unit-of-work design across a modular service layer.
## What propagation means `@Transactional` in Spring wraps a method in a transaction using an AOP proxy. **Propagation** answers the question: 'when this method is called, and there might *already* be a transaction running, what should happen?' The setting is `@Transactional(propagation = Propagation.REQUIRED)`, and REQUIRED is the **default** — writing `@Transactional` alone gives you REQUIRED. ## The REQUIRED rule Exactly two cases: 1. **No transaction active** → Spring's `PlatformTransactionManager` (e.g. `DataSourceTransactionManager` for JDBC/JPA) **starts a new physical transaction**: it grabs a `Connection` from the `DataSource`, sets `autoCommit=false`, and binds that Connection to the current thread (via `TransactionSynchronizationManager`). 2. **A transaction is already active** → the method **joins (participates in) the existing one**. No new Connection, no new physical transaction. Spring just notes that another layer has entered. Because the Connection is bound to the thread, any `@Repository`/`JdbcTemplate`/JPA `EntityManager` used inside will transparently use that same Connection. ## Why it matters Consider `OrderService.placeOrder()` (`@Transactional`) calling `InventoryService.reserve()` (`@Transactional`). With REQUIRED on both, there is **one** transaction, **one** Connection. If `reserve()` fails, the entire `placeOrder()` rolls back — inventory and order changes are atomic. That 'all-or-nothing across service methods' behavior is exactly why REQUIRED is the sensible default. ## Terms defined - **Physical transaction**: the actual DB transaction on one Connection. - **Logical transaction**: each `@Transactional` scope entered. Nested REQUIRED calls create nested *logical* transactions inside *one* physical transaction. - **PlatformTransactionManager**: Spring's abstraction that begins/commits/rolls back; REQUIRED is interpreted by `AbstractPlatformTransactionManager`. ## Common gotcha (preview) Because REQUIRED joins the existing transaction, a rollback triggered inside the inner method dooms the whole shared transaction — you can't 'catch it and carry on' cleanly. That is covered in follow-up questions. ## When to use Use REQUIRED (the default) whenever a method should be part of the caller's atomic unit of work. Choose something else only for a deliberate reason: REQUIRES_NEW for an independent commit (audit log, outbox), SUPPORTS for read helpers, MANDATORY to assert a caller already opened one.
- What propagation is used if you write @Transactional with no arguments?Propagation.REQUIRED — it is the default. (The default isolation is also DEFAULT, meaning the database's default.)
- If placeOrder and reserve are both REQUIRED, how many database Connections are used?One. The inner call joins the outer's physical transaction and reuses the same thread-bound Connection.
saying these in an interview costs you the question
- Thinking REQUIRED always starts a brand-new transaction even when one is already active.
- Believing each @Transactional method gets its own Connection.
- Confusing REQUIRED with REQUIRES_NEW (which always suspends and starts a fresh transaction).