Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Interview Prep: 8+ Years (Senior & Lead)

Expert Core Java

  • Tricky Java Output, Operators & OOP Edge Cases — Interview Questions
  • Tricky Exceptions, Memory & Keyword Questions — Interview Questions
  • Classic Java Language Questions, Senior-Grade Answers — Interview Questions
  • Classic Collections, Threads & JDK APIs, Senior-Grade Answers — Interview Questions
  • Reflection, Dynamic Proxies, final & Modern OOP Design — Interview Questions

JVM Internals & Performance

  • Class Loading, Bytecode & Object Layout — Interview Questions
  • JIT Compilation & Runtime Optimisations — Interview Questions
  • Garbage Collectors Deep Dive — Interview Questions
  • JVM Tuning, GC Logs & Memory Footprint — Interview Questions
  • Memory Leaks, OutOfMemoryErrors & Profiling Tools — Interview Questions
  • Modules, Agents & Advanced JVM APIs — Interview Questions

Collections & Concurrency at Scale

  • Collections Internals & Complexity — Interview Questions
  • Iterators, Comparators & Ordering Contracts — Interview Questions
  • Concurrent Collections, Queues & Lock-Free Structures — Interview Questions
  • Threads, Executors & ForkJoin Internals — Interview Questions
  • Locks, Atomics, CAS & Synchronizers — Interview Questions
  • Java Memory Model, volatile, Fences & ThreadLocal — Interview Questions
  • Deadlock, Livelock, Starvation & Concurrent Design — Interview Questions
  • CompletableFuture, Parallel Streams & Non-Blocking I/O — Interview Questions

Modern Java (8 to 21+)

  • Lambdas & Functional Interfaces Internals — Interview Questions
  • Streams & Collectors Deep Dive — Interview Questions
  • Optional & Interface Default/Static Methods — Interview Questions
  • Java 9–25 Features & Virtual Threads — Interview Questions

Design Patterns, SOLID & Clean Code

  • Design Pattern Trade-offs & Combinations — Interview Questions
  • SOLID, Clean Code & Anti-Patterns — Interview Questions

Spring & Spring Boot Internals

  • IoC, Dependency Injection & Bean Lifecycle Internals — Interview Questions
  • Spring AOP, Proxies & @Async Internals — Interview Questions
  • Spring Configuration, Auto-Configuration & Custom Starters — Interview Questions
  • Spring MVC & REST Internals, Exception Frameworks — Interview Questions
  • Spring Security Advanced Internals — Interview Questions
  • Spring WebFlux, Reactor & R2DBC — Interview Questions
  • Spring Cloud, Observability & Distributed Tracing — Interview Questions
  • Spring Boot 3, Native Images & Production Scenarios — Interview Questions

JPA, Hibernate & Databases at Scale

  • Spring Data JPA — Queries, Projections, Custom Repositories & Locking — Interview Questions
  • JPA Entity Mapping, Associations & Cascades — Interview Questions
  • JPQL vs Native Queries in Depth — Interview Questions
  • Hibernate Caching — First-Level, Second-Level & Query Cache — Interview Questions
  • Lazy vs Eager Loading, LazyInitializationException & N+1 — Interview Questions
  • JPA Transactions, Propagation, Isolation & Dirty Checking — Interview Questions
  • SQL vs NoSQL, Indexing & Query Tuning — Interview Questions
  • Database Scaling, Replication, Pooling & Consistency Models — Interview Questions
  • Redis, Search, Time-Series, CDC & Transactional Data Modelling — Interview Questions

Testing Strategy & API Design

  • Spring Boot Test Slices, Context & Test Strategy — Interview Questions
  • Testing Web, Persistence, Security, Async & Messaging in Spring Boot — Interview Questions
  • JUnit 5 & Mockito, Advanced — Interview Questions
Chaturmind
← Java Interview Prep: 8+ Years (Senior & Lead)

Expert Core Java

  • Tricky Java Output, Operators & OOP Edge Cases — Interview Questions
  • Tricky Exceptions, Memory & Keyword Questions — Interview Questions
  • Classic Java Language Questions, Senior-Grade Answers — Interview Questions
  • Classic Collections, Threads & JDK APIs, Senior-Grade Answers — Interview Questions
  • Reflection, Dynamic Proxies, final & Modern OOP Design — Interview Questions

JVM Internals & Performance

  • Class Loading, Bytecode & Object Layout — Interview Questions
  • JIT Compilation & Runtime Optimisations — Interview Questions
  • Garbage Collectors Deep Dive — Interview Questions
  • JVM Tuning, GC Logs & Memory Footprint — Interview Questions
  • Memory Leaks, OutOfMemoryErrors & Profiling Tools — Interview Questions
  • Modules, Agents & Advanced JVM APIs — Interview Questions

Collections & Concurrency at Scale

  • Collections Internals & Complexity — Interview Questions
  • Iterators, Comparators & Ordering Contracts — Interview Questions
  • Concurrent Collections, Queues & Lock-Free Structures — Interview Questions
  • Threads, Executors & ForkJoin Internals — Interview Questions
  • Locks, Atomics, CAS & Synchronizers — Interview Questions
  • Java Memory Model, volatile, Fences & ThreadLocal — Interview Questions
  • Deadlock, Livelock, Starvation & Concurrent Design — Interview Questions
  • CompletableFuture, Parallel Streams & Non-Blocking I/O — Interview Questions

Modern Java (8 to 21+)

  • Lambdas & Functional Interfaces Internals — Interview Questions
  • Streams & Collectors Deep Dive — Interview Questions
  • Optional & Interface Default/Static Methods — Interview Questions
  • Java 9–25 Features & Virtual Threads — Interview Questions

Design Patterns, SOLID & Clean Code

  • Design Pattern Trade-offs & Combinations — Interview Questions
  • SOLID, Clean Code & Anti-Patterns — Interview Questions

Spring & Spring Boot Internals

  • IoC, Dependency Injection & Bean Lifecycle Internals — Interview Questions
  • Spring AOP, Proxies & @Async Internals — Interview Questions
  • Spring Configuration, Auto-Configuration & Custom Starters — Interview Questions
  • Spring MVC & REST Internals, Exception Frameworks — Interview Questions
  • Spring Security Advanced Internals — Interview Questions
  • Spring WebFlux, Reactor & R2DBC — Interview Questions
  • Spring Cloud, Observability & Distributed Tracing — Interview Questions
  • Spring Boot 3, Native Images & Production Scenarios — Interview Questions

JPA, Hibernate & Databases at Scale

  • Spring Data JPA — Queries, Projections, Custom Repositories & Locking — Interview Questions
  • JPA Entity Mapping, Associations & Cascades — Interview Questions
  • JPQL vs Native Queries in Depth — Interview Questions
  • Hibernate Caching — First-Level, Second-Level & Query Cache — Interview Questions
  • Lazy vs Eager Loading, LazyInitializationException & N+1 — Interview Questions
  • JPA Transactions, Propagation, Isolation & Dirty Checking — Interview Questions
  • SQL vs NoSQL, Indexing & Query Tuning — Interview Questions
  • Database Scaling, Replication, Pooling & Consistency Models — Interview Questions
  • Redis, Search, Time-Series, CDC & Transactional Data Modelling — Interview Questions

Testing Strategy & API Design

  • Spring Boot Test Slices, Context & Test Strategy — Interview Questions
  • Testing Web, Persistence, Security, Async & Messaging in Spring Boot — Interview Questions
  • JUnit 5 & Mockito, Advanced — Interview Questions
HomeLearnJava Interview PrepJava Interview Prep: 8+ Years (Senior & Lead)JPA, Hibernate & Databases at Scale
✓ FreeAdvanced· 10 min read

JPA Transactions, Propagation, Isolation & Dirty Checking — Interview Questions

REQUIRED vs REQUIRES_NEW, rolling back "nested" transactions and how Spring simulates nesting (savepoints), isolation levels in JPA and the database defaults, @Transactional on private methods and on interfaces, checked vs unchecked exception rollback and rollbackFor, when a transaction really begins and commits in Spring Data JPA, the EntityManager in the transaction lifecycle, dirty checking and flush modes, read-only transactions that don't flush, transaction timeouts and deadlock detection, and LazyInitializationException causes.

Published September 25, 2026


How to use this lesson

Transaction bugs are silent data bugs:

  • partial commits;
  • rollbacks that don't happen;
  • changes saved when they shouldn't be;
  • deadlocks under load.

Tie every answer to the proxy (where the transaction starts), the persistence context (when the SQL is actually issued), and the database (the isolation behaviour).

Q1. What's the difference between Propagation.REQUIRED and REQUIRES_NEW?

Short answer:

  • REQUIRED (the default): join the current transaction if one exists, otherwise start one. Everything commits or rolls back together. An exception in the inner method marks the shared transaction rollback-only.
  • REQUIRES_NEW: suspend the current transaction, and start an independent one. It commits or rolls back on its own, regardless of the outer transaction's outcome. It's used for audit logs, error records, or outbox and ID allocation that must persist even if the main work fails.

The costs of REQUIRES_NEW:

  • it takes a second database connection while the outer one is suspended, which risks pool exhaustion, or deadlock under load;
  • the inner transaction can't see the outer one's uncommitted changes;
  • it can deadlock with the outer transaction if both touch the same rows.

Learn it in depth → @Transactional Deep Dive

Q2. What happens when "nested" transactions roll back? Can JPA do nested transactions, and how does Spring simulate them?

Short answer: JPA has no true nested transactions.

  • With REQUIRED, there's one physical transaction. An inner failure marks it rollback-only. If the outer code catches the exception and tries to commit, Spring throws UnexpectedRollbackException, and everything is rolled back.
  • Propagation.NESTED simulates nesting with JDBC savepoints. The inner scope rolls back to the savepoint, and the outer transaction can continue. It's supported by DataSourceTransactionManager/JdbcTransactionManager, but not by JpaTransactionManager (Hibernate's persistence context can't be partially rolled back cleanly).
  • REQUIRES_NEW provides independent transactions (not nested ones). The inner commit survives an outer rollback, and vice versa.

Q3. How is transaction isolation handled in JPA? Which isolation levels are supported, and which is the default?

Short answer: JPA itself defines no isolation API. The isolation is the JDBC connection's isolation level, set by:

  • @Transactional(isolation = Isolation.REPEATABLE_READ) (Spring sets it on the connection; JpaTransactionManager supports it through the JPA dialect);
  • or the pool or database defaults.

The levels: READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ and SERIALIZABLE (with DEFAULT meaning "use the database's default").

The database defaults: PostgreSQL, Oracle and SQL Server use READ COMMITTED. MySQL InnoDB uses REPEATABLE READ.

Beyond the database:

  • the persistence context gives application-level repeatable reads of entities already loaded;
  • optimistic locking (@Version) handles lost updates without raising the isolation level;
  • pessimistic locks (SELECT … FOR UPDATE) protect specific rows.

Common trap: higher isolation levels reduce concurrency, and cause more serialisation failures and deadlocks, which you must retry.

Learn it in depth → Transactions & Isolation Levels

Q4. What does @Transactional on a private method mean?

Short answer: Nothing: it's ignored. Spring applies @Transactional through proxies, which can only intercept calls from outside the bean to proxyable (public, or with CGLIB, protected and package-private) methods. A private method is never intercepted, so no transaction is created. Since Spring 6, class-based proxies also advise protected and package-private methods, but never private ones, and never self-invocations. Fix it by moving the method to a separate bean, making it public and calling it through the proxy, using TransactionTemplate, or using AspectJ mode.

Q5. Can @Transactional be used on an interface, or on interface methods?

Short answer: It works in current Spring versions: annotations on interface methods are detected for both JDK and CGLIB proxies (since Spring 5 or 6). But the recommendation is to put @Transactional on concrete classes and methods:

  • it keeps transaction semantics next to the implementation;
  • other annotation-driven tools, or AspectJ mode, may not see interface annotations (Java annotations aren't inherited from interfaces);
  • it's confusing when several implementations need different settings.

Spring Data repositories already declare transactional defaults on SimpleJpaRepository: readOnly = true on reads, and read-write on save and delete.

Q6. How do checked and unchecked exceptions differ for rollback? What does rollbackFor do? What happens when an inner transactional method throws a checked exception?

Short answer: By default, Spring rolls back only on unchecked exceptions (RuntimeException, Error), and commits on checked exceptions. That's inherited from EJB conventions, on the idea that checked exceptions represent expected business outcomes. So when an inner @Transactional method throws a checked exception (say InsufficientFundsException extends Exception), the transaction isn't marked rollback-only, and the changes made before it commit, unless you configure it:

  • rollbackFor = Exception.class (or specific types) rolls back on those checked exceptions too;
  • noRollbackFor = ... keeps the commit, for specific runtime exceptions;
  • Spring 6.1 added a global switch: @EnableTransactionManagement(rollbackOn = RollbackOn.ALL_EXCEPTIONS).

The practice: use unchecked domain exceptions, or set rollbackFor consistently (through a meta-annotation like @BusinessTransactional).

Q7. When does a transaction actually begin and commit in Spring Data JPA?

Short answer:

  • It begins when a call enters a @Transactional proxy boundary: your service method, or, if there's none, the repository method itself, since SimpleJpaRepository methods are transactional. The JpaTransactionManager binds an EntityManager and a JDBC connection to the thread. With DataSources configured for it, the connection may be acquired lazily (LazyConnectionDataSourceProxy, or Hibernate's DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION handling mode).

  • SQL is not executed immediately on save(): inserts and updates are queued in the persistence context, and flushed:

    • at commit;
    • before queries that could be affected (FlushModeType.AUTO);
    • or on explicit flush()/saveAndFlush().

    Identity-generated IDs (GenerationType.IDENTITY) force an immediate INSERT, to obtain the ID.

  • It commits when the outermost transactional method returns normally: flush, then JDBC commit, then @TransactionalEventListener(AFTER_COMMIT) callbacks. It rolls back when a rollback-triggering exception propagates out.

Common trap: without a service-level @Transactional, each repository call is its own transaction, so a multi-step operation is not atomic.

Q8. What's the EntityManager's role in the transaction lifecycle?

Short answer: The EntityManager is the persistence context, the unit of work:

  • it tracks managed entities (persist, find, merge, remove) and their snapshots;
  • it performs dirty checking, and orders and flushes the SQL (inserts, updates, deletes, respecting FKs);
  • it's bound to the transaction: Spring injects a shared, transaction-scoped proxy (@PersistenceContext), which delegates to the EntityManager bound to the current transaction;
  • it's cleared or closed at the end, which detaches its entities (later changes aren't saved unless merged);
  • it's the source of lazy loading, which needs it to still be open.

flush() synchronises with the database (without committing), clear() detaches everything (useful in batches), and refresh() reloads the database state.

Q9. What is dirty checking, and when is it triggered?

Short answer: When an entity becomes managed (loaded or persisted), Hibernate keeps a snapshot of its state. At flush time, it compares every managed entity with its snapshot (or uses enhanced dirty tracking), and issues UPDATE statements for the changed ones, without any explicit save() call. The flush is triggered:

  • before commit;
  • before JPQL or native queries that might read the affected tables (with the AUTO flush mode);
  • or on an explicit flush().

The implications:

  • modifying an entity inside a transaction persists it, even if you didn't intend to (for example, "just computing" on an entity), so beware of mutating managed entities for display;
  • the cost grows with the number of managed entities (for huge batches, use clear() or StatelessSession, or read-only mode);
  • @DynamicUpdate updates only the changed columns (a trade-off: no cached SQL);
  • detached entities aren't checked until they're merged.

Q10. How do you make sure read-only transactions don't flush changes? How do you avoid unwanted flushes?

Short answer:

  • @Transactional(readOnly = true): Spring passes the hint through to Hibernate, which sets the session's FlushMode.MANUAL (no automatic flush) and read-only mode for loaded entities (no snapshots, and no dirty checking, which saves memory and CPU). With some drivers and pool setups, it also sets Connection.setReadOnly(true) (it can route to replicas, or enable database optimisations).
  • Per query: @QueryHints(@QueryHint(name = HibernateHints.HINT_READ_ONLY, value = "true")), or session.setDefaultReadOnly(true).
  • Detach or clear entities you don't want tracked, and use projections (DTOs are never dirty-checked).
  • Avoid mutating managed entities for presentation. Map them to DTOs first.

Common trap: readOnly isn't a security guarantee on every stack. An explicit flush(), or a modifying query, can still write, depending on the provider, and the database connection's read-only flag.

Q11. How do transaction timeouts and deadlock detection work?

Short answer:

  • Timeouts: @Transactional(timeout = 5) (seconds). Spring's JPA and JDBC support applies the remaining time as the JDBC statement query timeout on each statement (and checks the deadline between operations), so long-running statements are cancelled, and the transaction rolls back (QueryTimeoutException/TransactionTimedOutException). It doesn't interrupt Java code that isn't talking to the database. Also configure database-level limits (statement_timeout, lock_timeout, idle_in_transaction_session_timeout in Postgres) as a safety net.

  • Deadlock detection is done by the database:

    • Postgres runs its detector after deadlock_timeout (1 second);
    • InnoDB detects deadlocks immediately (or relies on innodb_lock_wait_timeout).

    The database kills a victim transaction with an error, which Spring translates into CannotAcquireLockException/DeadlockLoserDataAccessException. The application should retry the whole transaction (idempotently, with backoff: Spring Retry's @Retryable placed outside @Transactional).

  • Prevention: acquire locks in a consistent order, keep transactions short, use the right indexes (so fewer rows are locked), and use SKIP LOCKED or NOWAIT for work queues.

Q12. What commonly causes LazyInitializationException, and how do you prevent it?

Short answer: Causes:

  • accessing a lazy association after the transaction or session ends: in controllers or views with OSIV disabled, during JSON serialisation of entities, in toString/logging after the service returns, and in async threads or scheduled jobs without a transaction;
  • entities cached (Spring @Cacheable) and used later;
  • a self-invocation that skipped @Transactional.

Prevention:

  • fetch what you need inside the transaction: join fetch, an entity graph, or batch fetching;
  • return DTOs from services;
  • mark service methods @Transactional(readOnly = true) when they navigate associations;
  • keep OSIV disabled, so these problems are caught early in tests;
  • never use enable_lazy_load_no_trans.

Follow-up questions this topic invites — and their answers

Q: What is TransactionTemplate, and when do you prefer it? A: Programmatic transaction boundaries (tx.execute(status -> …)). Prefer it for fine-grained control inside one method: several transactions in one method, conditional rollback (status.setRollbackOnly()), or code that can't be proxied.

Q: How do @TransactionalEventListener phases work? A: Listeners run relative to the publishing transaction: BEFORE_COMMIT, AFTER_COMMIT (the default), AFTER_ROLLBACK or AFTER_COMPLETION. If there's no transaction, the listener doesn't run unless fallbackExecution = true. Use AFTER_COMMIT for side effects (emails, messages) that must not fire on rollback.

Q: Why might a @Transactional test not reveal a bug? A: Test-managed transactions roll back at the end, and the persistence context may serve entities from memory, so flush problems, constraint violations or lazy-loading issues can go unnoticed. Call flush() in tests, or run some tests without a test transaction.

Q: What's the difference between persist and merge? A: persist makes a new instance managed (it fails for detached entities with IDs). merge copies the state of a detached or new instance onto a managed copy, and returns that copy. The argument stays detached, which is a common source of bugs.

Previous

Lazy vs Eager Loading, LazyInitializationException & N+1 — Interview Questions

Next

SQL vs NoSQL, Indexing & Query Tuning — Interview Questions

AI Tutor

Lesson: JPA Transactions, Propagation, Isolation & Dirty Checking — Interview Questions

Quick actions

AI responses can be inaccurate. Verify critical information.