Spring Transaction Source Code

Spring provides a unified transaction abstraction layer that decouples underlying transaction implementations—such as JDBC, JPA, Hibernate, and JTA—while offering both declarative (AOP-based) and programmatic management styles. The core philosophy centers around three primary components:

  • PlatformTransactionManager handles transaction initiation, commitment, and rollback.
  • TransactionDefinition outlines transaction attributes including propagation behavior, isolation levels, and timeouts.
  • TransactionStatus monitors the runtime state of an active transaction.

At runtime, Spring selects the appropriate PlatformTransactionManager implementation based on your configuration, seamlessly managing disparate resource types under a single unified architecture.


Interface Primary Role Key Methods
PlatformTransactionManager Transaction gateway; manages the transaction lifecycle getTransaction(TransactionDefinition), commit(TransactionStatus), rollback(TransactionStatus)
TransactionDefinition Defines transaction attributes getPropagationBehavior(), getIsolationLevel(), getTimeout(), isReadOnly()
TransactionStatus Tracks runtime transaction states isNewTransaction(), hasSavepoint(), isCompleted()

Customizing Transaction Attributes Programmatically

TransactionDefinition def = new DefaultTransactionDefinition();
((DefaultTransactionDefinition) def).setPropagationBehavior(
        TransactionDefinition.PROPAGATION_REQUIRED);
((DefaultTransactionDefinition) def).setIsolationLevel(
        TransactionDefinition.ISOLATION_READ_COMMITTED);

Common Transaction Manager Implementations

Implementation Class Target Scenario Key Source Code Location
DataSourceTransactionManager Pure JDBC environments org.springframework.jdbc.datasource.DataSourceTransactionManager
JpaTransactionManager JPA (EntityManager) environments org.springframework.orm.jpa.JpaTransactionManager
HibernateTransactionManager Native Hibernate (Session) environments org.springframework.orm.hibernate5.HibernateTransactionManager
JtaTransactionManager Distributed transactions (JTA) org.springframework.transaction.jta.JtaTransactionManager

Core Workflow of DataSourceTransactionManager

public TransactionStatus getTransaction(TransactionDefinition definition) {
    // 1. Acquire current connection (reuse if already bound to the thread)
    Connection con = DataSourceUtils.getConnection(this.dataSource);
    // 2. Configure auto-commit based on transaction attributes
    boolean previousAutoCommit = con.getAutoCommit();
    con.setAutoCommit(false);
    // 3. Create and return a DefaultTransactionStatus instance
    return new DefaultTransactionStatus(con, true, false,
            definition.isReadOnly(), false, null);
}
  • Connection Acquisition: Utilizing DataSourceUtils.getConnection ensures that database connections are safely reused across the same transactional synchronization context.
  • Auto-Commit Configuration: Disabling auto-commit allows subsequent explicit commit or rollback operations to take effect.
  • State Object Return: The DefaultTransactionStatus encapsulates connection details, flags for new transactions, and read-only statuses.

Key Implementation in JpaTransactionManager

protected EntityManagerHolder doBegin(Object transaction, TransactionDefinition definition) {
    EntityManagerFactory emf = this.entityManagerFactory;
    EntityManager em = emf.createEntityManager();
    // Bind the EntityManager holder to the current thread
    TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em));
    // Initiate the native JPA transaction
    em.getTransaction().begin();
    return new EntityManagerHolder(em);
}
  • An EntityManager is created and registered with the TransactionSynchronizationManager, ensuring that all DAO operations within the same transaction share an identical persistence context.
  • It triggers the native JPA transaction via em.getTransaction().begin() to officially start the unit of work.

Implementation Mechanism of Declarative Transactions

TransactionInterceptor

The TransactionInterceptor acts as a Spring AOP MethodInterceptor, weaving transactional behavior around target methods during execution.

public Object invoke(MethodInvocation invocation) throws Throwable {
    // 1. Resolve transaction attributes matching the invoked method
    TransactionAttribute txAttr = this.attributeSource.getTransactionAttribute(
            invocation.getMethod(), invocation.getThis().getClass());
    // 2. Proceed directly if no transaction attribute is found
    if (txAttr == null) {
        return invocation.proceed();
    }
    // 3. Initialize transaction info and retrieve the transaction status
    TransactionInfo txInfo = createTransactionIfNecessary(txAttr, methodName);
    try {
        // 4. Execute the underlying business logic
        Object retVal = invocation.proceed();
        // 5. Commit the transaction upon successful completion
        commitTransactionAfterReturning(txInfo);
        return retVal;
    } catch (Throwable ex) {
        // 6. Roll back the transaction when an exception is thrown
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
    } finally {
        // 7. Clean up transaction resources and unbind contexts
        cleanupTransactionInfo(txInfo);
    }
}

Sources of Transaction Attributes

  • XML configuration: Elements like <tx:advice> and <tx:method>.
  • Annotations: @Transactional (parsed via AnnotationTransactionAttributeSource).
  • Java Configuration: @EnableTransactionManagement combined with @Bean definitions.

Transaction Synchronization

Spring triggers TransactionSynchronization callbacks before and after transaction commits or rollbacks. These hooks enable deferred resource cleanup, cache flushing, and other lifecycle-dependent tasks.

public interface TransactionSynchronization {
    void beforeCommit(boolean readOnly);
    void afterCommit();
    void beforeCompletion();
    void afterCompletion(int status);
}

Common implementations include:

  • DataSourceTransactionManager registering a ConnectionHolder to release JDBC connections inside the afterCompletion phase.
  • JpaTransactionManager cleaning up and closing the active EntityManager within afterCompletion.

Enabling Transaction Management

XML-Based Configuration

<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

Java-Based Configuration

@Configuration
@EnableTransactionManagement
public class TxConfig {

    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create()
                .url("jdbc:h2:mem:test")
                .username("sa")
                .build();
    }

    @Bean
    public PlatformTransactionManager txManager(DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }
}

@EnableTransactionManagement automatically registers the TransactionInterceptor and BeanFactoryTransactionAttributeSourceAdvisor to weave AOP proxies into your application context.


Practical Example: Declarative Transaction Flow

@Service
public class OrderService {

    @Autowired
    private OrderDao orderDao;
    @Autowired
    private StockDao stockDao;

    @Transactional(propagation = Propagation.REQUIRED,
                   isolation = Isolation.READ_COMMITTED,
                   timeout = 30,
                   rollbackFor = Exception.class)
    public void createOrder(Order order) {
        orderDao.insert(order);                  // Insert record into order table
        stockDao.decrease(order.getSkuId(), order.getQty()); // Deduct inventory
        // Triggers a rollback if a RuntimeException occurs due to insufficient stock
    }
}
  • Propagation: REQUIRED joins an existing transaction if present; otherwise, it creates a new one.
  • Isolation: READ_COMMITTED prevents dirty reads.
  • Timeout: Automatically rolls back if execution exceeds 30 seconds.
  • Rollback Rules: Any instance of Exception or its subclasses triggers a rollback.

Tips for Debugging Transaction Source Code

  1. Enable DEBUG Logging:
    logging.level.org.springframework.transaction=DEBUG
    logging.level.org.springframework.jdbc.datasource=DEBUG
    
  2. Use TransactionSynchronizationManager.isActualTransactionActive() to check whether the current thread is operating inside an active transaction.
  3. Inspect TransactionInfo (an internal helper class within TransactionInterceptor) to examine active transaction attributes, statuses, and synchronization callbacks.
  4. Set IDE Breakpoints inside DataSourceTransactionManager.doBegin, commit, and rollback to observe real-time modifications to connection auto-commit states.

Summary

The Spring transaction framework uses a unified abstraction combined with multiple implementations design, allowing developers to switch between different persistence technologies effortlessly. The core execution pipeline can be summarized as follows:

  1. Resolve transaction attributes via TransactionAttributeSource.
  2. Obtain or create a transaction using PlatformTransactionManager.getTransaction.
  3. Execute business logic intercepted by the TransactionInterceptor AOP aspect.
  4. Commit or roll back based on the execution outcome (commit / rollback).
  5. Synchronize resource cleanup through TransactionSynchronization.

Mastering these implementation details empowers you to handle advanced transaction control, performance tuning, and troubleshooting effectively in real-world enterprise applications.