Lesson 9 · Data Management

Transactions

@Transactional, propagation, rollback rules, isolation — the most heavily-tested topic in this section.

What you'll be tested on The default propagation and what REQUIRES_NEW does; which exceptions roll back by default (and how to change it); the isolation levels and what each allows; and — reusing Lesson 6 — that @Transactional is proxy-based, so self-invocation bypasses it.

Two styles, one abstraction

Both sit on top of PlatformTransactionManager, the central strategy interface. Enable declarative transactions with @EnableTransactionManagement (Spring Boot switches it on automatically).

@Transactional is proxy-based (Lesson 6 returns) Because a proxy intercepts the call, (1) by default only public methods are transactional, and (2) self-invocation — calling this.otherTxMethod() — bypasses the proxy, so that method's transaction settings are ignored. This is the classic transaction bug.

Pick the right transaction manager

ImplementationUse with
DataSourceTransactionManagerPlain JDBC / JdbcTemplate / MyBatis
JpaTransactionManagerJPA (Hibernate, EclipseLink…)
HibernateTransactionManagerNative Hibernate
JtaTransactionManagerGlobal / distributed (multiple resources — XA)

Propagation — how methods join or create transactions

PropagationBehaviour
REQUIRED defaultJoin the current transaction, or create one if none exists
REQUIRES_NEWAlways start a new transaction, suspending any existing one
NESTEDRun in a nested transaction (savepoint) if one exists; else like REQUIRED
SUPPORTSJoin if one exists; else run non-transactionally
NOT_SUPPORTEDRun non-transactionally, suspending any existing transaction
MANDATORYMust run in an existing transaction, else throw
NEVERMust not run in a transaction, else throw

Use the current transaction if there is one: REQUIRED, SUPPORTS, MANDATORY. Always get a fresh transaction: REQUIRES_NEW.

Rollback rules

The default rule — memorise it exactly Spring rolls back automatically on unchecked exceptions (RuntimeException) and Error — but not on checked exceptions (a checked exception commits by default!).

Isolation levels

LevelDirty readNon-repeatable readPhantom read
READ_UNCOMMITTED❌ possible❌ possible❌ possible
READ_COMMITTED✅ prevented❌ possible❌ possible
REPEATABLE_READ❌ possible
SERIALIZABLE

SERIALIZABLE is the most restrictive (safest, slowest); DEFAULT uses the database's own default. Non-repeatable reads can still happen at READ_UNCOMMITTED and READ_COMMITTED.

Transactions in tests

Tests roll back by default A test annotated @Transactional runs each test method in a transaction that is rolled back at the end — so your tests don't pollute the database. Override with @Commit (or @Rollback(false)).

ACID, quickly: Atomicity (all-or-nothing), Consistency, Isolation, Durability (committed changes survive a crash). A local transaction spans one resource; a global/distributed (JTA/XA) transaction spans several (multiple databases, message queues).

Primary source — read this
Spring Framework 5.3 — Data Access: Declarative Transaction Management

Read "Understanding the Spring Framework Transaction Abstraction", "Using @Transactional", and "Rolling Back a Declarative Transaction".

Check yourself

The default-rollback rule, isolation levels, and the self-invocation trap are the highest-value questions. Covers your book's whole Transaction section. Options shuffle on every load.

Second pass The same ground is in your book's Transaction section (15 questions) — isolation levels, propagation, rollback, ACID, local vs global. A high-value topic worth over-drilling.
I'm your teacher — ask me anything. Want the two-bean fix that makes a REQUIRES_NEW actually start (defeating self-invocation), or a walk-through of when to use NESTED? Ask. Say "continue" for Lesson 10 — Spring Data JPA.
← Lesson 8 · Spring JDBC Lesson 10 · Spring Data JPA → (coming next)