Backend Development 13 min read

Understanding Spring Transaction Management: @EnableTransactionManagement, Transaction Propagation, and Synchronization

This article explains how Spring enables transaction management through @EnableTransactionManagement, details the underlying proxy mechanism, outlines the basic and detailed execution flow, describes transaction propagation types and their classifications, and shows how to force rollback and use TransactionSynchronization for custom callbacks.

Top Architect
Top Architect
Top Architect
Understanding Spring Transaction Management: @EnableTransactionManagement, Transaction Propagation, and Synchronization

Spring transaction management is essentially enabled by adding an @EnableTransactionManagement annotation, which registers two beans: AutoProxyRegistrar and ProxyTransactionManagementConfiguration . The former registers an InfrastructureAdvisorAutoProxyCreator bean that creates automatic proxies, while the latter defines three additional beans: BeanFactoryTransactionAttributeSourceAdvisor , AnnotationTransactionAttributeSource , and TransactionInterceptor .

The AnnotationTransactionAttributeSource checks whether a class or method is annotated with @Transactional . When such an annotation is present, the TransactionInterceptor intercepts the method call, creates a proxy, and routes the execution to its invoke() method.

1. @EnableTransactionManagement Working Principle

Enabling Spring transactions adds an Advisor to the container, which ultimately registers the two beans mentioned above.

2. Basic Execution Principle

During bean creation, InfrastructureAdvisorAutoProxyCreator checks if the bean matches BeanFactoryTransactionAttributeSourceAdvisor . If the bean or any of its methods has @Transactional , a dynamic proxy is created.

When the proxy method is invoked, it again checks for a matching advisor and then executes the TransactionInterceptor 's invoke() method, which follows these steps:

Use the configured PlatformTransactionManager to obtain a new database connection.

Set the connection's autocommit to false.

Execute the business method (SQL statements).

If no exception occurs, commit the transaction.

If an exception occurs, roll back the transaction.

3. Detailed Execution Flow

The article provides a flow diagram (link omitted) illustrating the above steps in detail.

4. Transaction Propagation Mechanism

When one method calls another, different propagation scenarios arise (e.g., both methods in the same transaction, separate transactions, or a mix). Spring handles these by checking the current thread's ThreadLocal for an existing connection; if one exists, it may suspend it, create a new connection, and later resume the original.

5. Propagation Categories

Examples of propagation types include REQUIRED (default), REQUIRES_NEW , etc. The article presents four case studies with code snippets demonstrating how each propagation behaves when exceptions are thrown.

@Component
public class UserService {
    @Autowired
    private UserService userService;

    @Transactional
    public void test() {
        // sql in test method
        userService.a();
    }

    @Transactional
    public void a() {
        // sql in a method
    }
}

Case 1 (REQUIRED) creates a single transaction for both methods; Case 2 rolls back both when an exception occurs; Case 3 also rolls back both; Case 4 uses Propagation.REQUIRES_NEW to create a separate transaction for the inner method, which rolls back independently before the outer transaction also rolls back.

6. Forced Rollback

If an exception is caught but you still want the transaction to roll back, call TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); inside the catch block.

@Transactional
public void test(){
    try {
        b();
    } catch (Exception e) {
        // build friendly error message
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}

public void b() throws Exception {
    throw new Exception();
}

7. TransactionSynchronization

Spring allows registration of TransactionSynchronization callbacks to listen to transaction lifecycle events such as suspend, resume, beforeCommit, beforeCompletion, afterCommit, and afterCompletion.

@Transactional
public void test(){
    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
        @Override public void suspend(){ System.out.println("test suspended"); }
        @Override public void resume(){ System.out.println("test resumed"); }
        @Override public void beforeCommit(boolean readOnly){ System.out.println("test before commit"); }
        @Override public void beforeCompletion(){ System.out.println("test before completion"); }
        @Override public void afterCommit(){ System.out.println("test after commit"); }
        @Override public void afterCompletion(int status){ System.out.println("test after completion"); }
    });
    jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
    userService.a();
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void a(){
    // similar synchronization registration
    jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
}

The article concludes with a reminder that the content is for educational purposes and includes promotional messages unrelated to the technical content.

JavaDatabasebackend developmentSpringSynchronizationtransaction managementPropagation
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.