What does the `isolation` attribute of `@Transactional` control, and what are the five values Spring offers?
answer
- I in ACID — the visibility knob
- Isolation enum: DEFAULT + 4 real levels
- Maps to JDBC Connection.setTransactionIsolation
- Higher = more consistent, less concurrent
- DEFAULT = let the DB decide
basics
~10 sIt sets how much one transaction is shielded from data other in-flight transactions are changing. Spring's Isolation enum offers DEFAULT, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, and SERIALIZABLE — higher levels give more consistency but less concurrency.
solid answer
~40 s`isolation` controls how visible concurrent transactions' uncommitted or committed changes are to the current transaction — the classic trade-off between consistency and concurrency. Spring's `org.springframework.transaction.annotation.Isolation` enum has five values: `DEFAULT` (use the database's own default), `READ_UNCOMMITTED`, `READ_COMMITTED`, `REPEATABLE_READ`, and `SERIALIZABLE`. Spring maps these onto the JDBC `Connection` isolation constants; the transaction manager applies the level to the physical connection when the transaction starts. Higher levels progressively prevent read anomalies (dirty, non-repeatable, phantom reads) but cost throughput through more locking or aborts. `DEFAULT` is by far the most common in real apps — you let the DB decide (often READ_COMMITTED on Postgres/Oracle, REPEATABLE_READ on MySQL InnoDB) and only override when a specific consistency requirement demands it.
code
java · 16 linesimport org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@Service
public class AccountService {
// Let the database pick its own default level (the common case).
@Transactional
public Account load(long id) { /* ... */ }
// Override only where a stronger guarantee is required.
@Transactional(isolation = Isolation.SERIALIZABLE)
public void transfer(long from, long to, BigDecimal amount) {
// ...
}
}go deeper
Must name the five enum values and state the consistency-vs-concurrency trade-off.
Should know it maps to JDBC connection isolation and that DEFAULT defers to the DB.
Explains when Spring physically applies and resets the level, and why DEFAULT is the pragmatic norm.
Frames isolation as a per-operation tuning decision balanced against lock contention and DB engine behavior.
## What isolation means When many transactions run at once, one transaction can accidentally see intermediate or changing data produced by another. **Isolation level** is the knob that decides how much a transaction is protected from those concurrent effects. It is one of the four ACID properties (the *I*). ## The Spring attribute You set it declaratively: ```java @Transactional(isolation = Isolation.REPEATABLE_READ) ``` The enum is `org.springframework.transaction.annotation.Isolation` with five constants: | Spring value | JDBC constant | Meaning | |---|---|---| | `DEFAULT` | (-1) | Don't override — use the datastore's own default level | | `READ_UNCOMMITTED` | `TRANSACTION_READ_UNCOMMITTED` (1) | Weakest; can see uncommitted data | | `READ_COMMITTED` | `TRANSACTION_READ_COMMITTED` (2) | Only see committed data | | `REPEATABLE_READ` | `TRANSACTION_REPEATABLE_READ` (4) | Re-reading a row gives the same value | | `SERIALIZABLE` | `TRANSACTION_SERIALIZABLE` (8) | Strongest; transactions behave as if run one-at-a-time | ## How Spring applies it When the transaction manager (`DataSourceTransactionManager`, `JpaTransactionManager`, etc.) begins a **new physical transaction**, it takes the JDBC `Connection` and calls `connection.setTransactionIsolation(level)` (unless the value is `DEFAULT`). After the transaction ends, Spring resets the connection to its prior level before returning it to the pool. Because the level lives on the connection, it is set **once when the transaction/connection starts** — you cannot meaningfully change it partway through. ## The consistency vs. concurrency trade-off Going up the levels prevents more anomalies but reduces parallelism: databases achieve higher levels with more/longer locks or with snapshot-and-abort schemes, so you get more blocking, more serialization failures, or lower throughput. That is why `DEFAULT` (letting the DB pick, usually READ_COMMITTED-ish) is the pragmatic norm, and you raise it only for the specific method that needs stronger guarantees. ## Gotchas - `DEFAULT` does **not** mean READ_COMMITTED everywhere — MySQL InnoDB defaults to REPEATABLE_READ, Oracle/Postgres to READ_COMMITTED. - Not every database supports every level (Oracle has no READ_UNCOMMITTED or REPEATABLE_READ). - The level only takes effect where a real transaction/connection is created — it is ignored when a method merely *joins* an already-running transaction (see propagation).
- What does `Isolation.DEFAULT` actually resolve to?It tells Spring not to override anything, so the effective level is whatever the underlying database defines as its default — e.g. READ_COMMITTED on PostgreSQL/Oracle, REPEATABLE_READ on MySQL InnoDB. It is database-specific, not a fixed level.
- Where in the lifecycle is the isolation level applied?When the transaction manager begins a new physical transaction it calls `Connection.setTransactionIsolation(...)` on the JDBC connection, and restores the original level when the transaction completes and the connection returns to the pool.
saying these in an interview costs you the question
- Saying DEFAULT always equals READ_COMMITTED
- Thinking isolation controls whether a method runs in a transaction at all (that's propagation)
- Believing you can change the level in the middle of a transaction