Master Spring Transaction Management: ACID, Isolation Levels, and Propagation

This article explains Spring's transaction mechanism, covering its reliance on database support, ACID properties, isolation levels, propagation attributes, programmatic and declarative management styles, and the underlying AOP implementation with concrete code examples.

Architect Chen
Architect Chen
Architect Chen
Master Spring Transaction Management: ACID, Isolation Levels, and Propagation

What Is Spring Transaction?

Spring itself does not implement transaction logic; it merely provides an abstraction over the underlying database's transaction capabilities. By combining Spring IoC and Spring AOP, developers can use declarative transactions that require no invasive code changes. When using plain JDBC, a typical transaction involves five steps: obtaining a connection, disabling auto‑commit, performing CRUD operations, committing or rolling back, and finally closing the connection. Spring handles all steps except the business logic (step 3).

1、获取连接 Connection con = DriverManager.getConnection();
2、开启事务 con.setAutoCommit(true/false);
3、执行CRUD
4、提交事务/回滚事务 con.commit() / con.rollback();
5、关闭连接 conn.close();

ACID Properties

Transactions guarantee four essential properties—Atomicity, Consistency, Isolation, and Durability. Atomicity ensures that a series of actions either all succeed or have no effect. Consistency requires the database to remain in a valid state before and after the transaction. Isolation prevents concurrent transactions from interfering with each other, and Durability makes committed changes permanent.

Isolation Levels in Spring

Spring maps the standard JDBC isolation levels to five options:

DEFAULT : Uses the database's default isolation.

READ_UNCOMMITTED : Allows dirty reads; the lowest isolation.

READ_COMMITTED : Prevents dirty reads but may allow non‑repeatable reads and phantom reads.

REPEATABLE_READ : Prevents dirty and non‑repeatable reads; phantom reads may still occur.

SERIALIZABLE : Highest cost, fully prevents dirty reads, non‑repeatable reads, and phantom reads by executing transactions sequentially.

Propagation Attributes

Spring defines seven PROPAGATION_ constants that control how a transaction joins or creates a new one. The diagram in the original article illustrates each mode (e.g., REQUIRED, REQUIRES_NEW, NESTED, etc.).

Two Management Approaches

Spring supports both programmatic (code‑driven) and declarative (annotation‑driven) transaction management.

Programmatic Transaction Management

Developers can use TransactionTemplate or PlatformTransactionManager to define transaction boundaries explicitly. The community generally recommends TransactionTemplate for its callback‑style simplicity.

@Autowired
private TransactionTemplate transactionTemplate;

public void testTransaction() {
    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
        @Override
        protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
            try {
                // ... business logic ...
            } catch (Exception e) {
                // rollback
                transactionStatus.setRollbackOnly();
            }
        }
    });
}

Declarative Transaction Management

Using the @Transactional annotation (or XML configuration) lets Spring create proxies that start, commit, or roll back transactions automatically around the annotated method.

@Transactional
public void insert(String userName) {
    this.jdbcTemplate.update("insert into t_user (name) values (?)", userName);
}

Implementation Details (AOP)

Spring’s transaction support relies on AOP to weave transaction logic into target methods. The core interceptor is TransactionInterceptor, whose invoke() method obtains the target class, then delegates to invokeWithinTransaction. Inside, createTransactionIfNecessary builds a TransactionInfo object, binds transaction attributes to the current thread, and obtains a TransactionStatus from the configured PlatformTransactionManager.

@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = (invocation.getThis() != null ?
        AopUtils.getTargetClass(invocation.getThis()) : null);
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

The manager’s getTransaction() method creates a new transaction when none exists, validates timeout settings, and respects the propagation behavior (e.g., REQUIRED, REQUIRES_NEW, NESTED). For a new transaction, it calls startTransaction, which ultimately invokes DataSourceTransactionManager.doBegin to set the connection to manual‑commit mode.

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
    Object transaction = doGetTransaction();
    if (isExistingTransaction(transaction)) {
        return handleExistingTransaction(def, transaction, debugEnabled);
    }
    if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
        throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
    }
    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
        throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
    } else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
               def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
               def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
        SuspendedResourcesHolder suspendedResources = suspend(null);
        try {
            return startTransaction(def, transaction, debugEnabled, suspendedResources);
        } catch (RuntimeException | Error ex) {
            resume(null, suspendedResources);
            throw ex;
        }
    } else {
        // empty transaction (no actual DB transaction)
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    }
}

Summary of Spring Transaction Mechanics

Spring transaction management is essentially a combination of AOP‑based method interception and the underlying database’s transaction support. When a transactional method starts, Spring decides whether to begin a new transaction (setting auto‑commit to false) or join an existing one. After the method completes, Spring either commits the transaction or rolls it back if a specified exception occurs.

AOPSpringTransaction Management
Architect Chen
Written by

Architect Chen

Sharing over a decade of architecture experience from Baidu, Alibaba, and Tencent.

0 followers
Reader feedback

How this landed with the community

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.