skip to content

Which PlatformTransactionManager implementation would you choose for plain JDBC, for JPA, and for JTA — and what goes wrong if you use the JDBC one with JPA?

level: middleimportance: must knowfreq 55%

answer

  1. JDBC → DataSourceTransactionManager
  2. JPA → JpaTransactionManager (flushes EntityManager)
  3. JTA/XA/distributed → JtaTransactionManager
  4. Wrong manager = persistence context not bound/flushed
  5. Boot auto-configures the right one

basics

~10 s

Plain JDBC: DataSourceTransactionManager. JPA: JpaTransactionManager. JTA/distributed: JtaTransactionManager. Using the JDBC one with JPA fails to manage the EntityManager, so the persistence context isn't flushed/synchronized correctly.

solid answer

~40 s

The concrete implementation must match the resource: DataSourceTransactionManager for a single JDBC DataSource, JpaTransactionManager (or HibernateTransactionManager) for a JPA EntityManagerFactory, and JtaTransactionManager to delegate to an application server / standalone JTA coordinator for distributed or XA transactions. All satisfy the same PlatformTransactionManager contract, so @Transactional code is unchanged. If you wire DataSourceTransactionManager while using JPA, it only manages the raw JDBC Connection, not the EntityManager — Spring won't bind and flush the persistence context to the transaction, so writes may not be flushed at commit and lazy loading/first-level-cache behavior breaks. Spring Boot auto-configures the right one based on classpath and beans, which is why you rarely declare it manually.

code

java · 22 lines
java
@Configuration
public class TxConfig {

    // Plain JDBC / MyBatis
    @Bean
    DataSourceTransactionManager jdbcTxManager(DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }

    // JPA — manages the EntityManager, flushes the persistence context on commit
    @Bean
    JpaTransactionManager jpaTxManager(EntityManagerFactory emf) {
        return new JpaTransactionManager(emf);
    }

    // Distributed / XA across multiple resources (server- or standalone-provided)
    @Bean
    JtaTransactionManager jtaTxManager(jakarta.transaction.TransactionManager tm,
                                       jakarta.transaction.UserTransaction ut) {
        return new JtaTransactionManager(ut, tm);
    }
}

go deeper

for a junior

Name the three managers and map them to JDBC/JPA/JTA.

for a middle

Explain the failure mode of mismatching the manager to the resource and that Boot auto-selects.

for a senior

Discuss JPA+JdbcTemplate sharing a connection, flush timing, and multi-datasource strategies.

for a principal

Weigh JTA/XA cost vs. alternatives (outbox, best-effort 1PC) and the reactive ReactiveTransactionManager split.

## The core idea `PlatformTransactionManager` is one interface with several implementations, each bridging Spring's uniform contract to a specific **transactional resource**. Picking the right one is essential because each knows how to *bind* its resource to the current transaction so the rest of Spring (repositories, templates) can find it. ## The main implementations - **`DataSourceTransactionManager`** (spring-jdbc) — for a **single JDBC `DataSource`**. It manages a `java.sql.Connection`, disabling autocommit and binding the connection to the thread via `TransactionSynchronizationManager` so `JdbcTemplate` reuses it. Use with plain JDBC or MyBatis. - **`JpaTransactionManager`** (spring-orm) — for a **JPA `EntityManagerFactory`**. It manages an `EntityManager`, binds it to the thread so `@PersistenceContext` and Spring Data JPA repositories share it, and flushes the persistence context before commit. It can also expose the underlying DataSource so plain `JdbcTemplate` calls join the same transaction. - **`HibernateTransactionManager`** (spring-orm) — the Hibernate-native equivalent when you use a Hibernate `SessionFactory` directly. - **`JtaTransactionManager`** (spring-tx) — delegates to a **JTA** (Java Transaction API) provider: a full transaction coordinator supplied by an application server or a standalone manager (e.g., Atomikos, Narayana). Use for **distributed/XA** transactions spanning multiple resources (two databases, a database + JMS). - **`R2dbcTransactionManager`** — reactive JDBC-style. Note: reactive stacks implement the sibling **`ReactiveTransactionManager`**, not `PlatformTransactionManager`. - **`JmsTransactionManager`** — for a JMS `ConnectionFactory` alone. ## What goes wrong with the wrong manager Using **`DataSourceTransactionManager` with JPA**: it wraps only the raw JDBC `Connection`. Spring does *not* bind an `EntityManager` to the transaction and does *not* trigger the persistence-context flush on commit. Symptoms: - Entity changes may not be flushed to the database at commit time (flush timing becomes unreliable). - `LazyInitializationException` can appear or disappear inconsistently because the EntityManager isn't transaction-scoped as expected. - Two data-access styles can end up on **different connections**, breaking atomicity. Conversely, `JpaTransactionManager` also cooperates with `JdbcTemplate` on the same DataSource, so mixing JPA and plain JDBC works when you choose the JPA manager. ## Multiple resources With **two DataSources**, one `PlatformTransactionManager` covers one resource only. Options: use **JTA/XA** for true two-phase commit, or register two managers and qualify `@Transactional("txManager2")`, accepting that each is an independent local transaction (no cross-resource atomicity). ## Spring Boot Spring Boot's `DataSourceTransactionManagerAutoConfiguration` / `JpaBaseConfiguration` auto-select the right implementation from the classpath (JPA present → `JpaTransactionManager`; JDBC only → `DataSourceTransactionManager`), so manual declaration is usually unnecessary. ## Rule of thumb Match the manager to the *highest-level* resource abstraction you use: JPA present → `JpaTransactionManager`; Hibernate-only → `HibernateTransactionManager`; plain JDBC/MyBatis → `DataSourceTransactionManager`; multiple/distributed resources → `JtaTransactionManager`.

  • If you use JPA but also make some JdbcTemplate calls, do they share the transaction?
    Yes, if you use JpaTransactionManager and both use the same DataSource. JpaTransactionManager binds the connection so JdbcTemplate joins the same physical transaction. Watch out: JPA writes flush at commit, so JdbcTemplate reads mid-method may not see unflushed entity changes.
  • How do you get true atomicity across two databases?
    Use JtaTransactionManager with an XA-capable JTA provider (two-phase commit). Two separate DataSourceTransactionManagers give two independent local transactions with no cross-resource atomicity.

saying these in an interview costs you the question

  • Saying any PlatformTransactionManager works with any resource — the manager must match the resource it binds.
  • Believing two DataSourceTransactionManagers give distributed/atomic commit across both databases.
  • Using DataSourceTransactionManager with JPA and expecting the persistence context to flush correctly.

context