Interpretation of Spring Transaction source code

The maven coordinates of the Spring Transaction specification are as follows:

 <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-tx</artifactId>
      <version>...</version>
    </dependency>

This package provides the spring transaction specification and the default jta (java transaction api) implementation (under the org.springframework.transaction.jta package), the specific implementation depends on different components, such as provided by spring-jdbc Implemented database transactions.

The core interface of Spring Transaction is transaction manager TransactionManager, but this interface is an identification interface, and the identification implementation class is a traditional or Reactive transaction manager. Traditional and Reactive transaction managers correspond to PlatformTransactionManager and ReactiveTransactionManager respectively. This article only focuses on traditional transaction managers.
spring-tx provides an abstract implementation of AbstractPlatformTransactionManager for the traditional transaction manager PlatformTransactionManager. Generally, custom transaction managers recommend inheriting the AbstractPlatformTransactionManager, such as spring -jdbc’s DataSourceTransactionManager inherits this abstract class. The uml class diagram of the spring-tx transaction manager is as follows:

For official specifications on spring transactions, please refer to: Spring Transaction Management

PlatformTransactionManager

Let’s take a look at the annotations for this interface:

central interface in Spring’s imperative transaction infrastructure. Typically, applications will work with either TransactionTemplate or declarative transaction demarcation through AOP. It is recommended to derive from the provided org. springframework.transaction.support.AbstractPlatformTransactionManager class, which pre-implements the defined propagation behavior and takes care of transaction synchronization handling.

public interface PlatformTransactionManager extends TransactionManager {<!-- -->
// According to the specified transaction propagation method, it is decided to return the running transaction or create a new transaction
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
\t
// Commit the transaction according to TransactionStatus, if the transaction is marked as rollback-only, perform a rollback
// If the current transaction is a nested inner transaction, the current commit will be ignored according to the transaction propagation method
void commit(TransactionStatus status) throws TransactionException;
\t
// implement rollback
// If the current transaction is not a new transaction (that is, a nested transaction), you only need to set the rollback-only attribute of the outer transaction according to different transaction propagation methods.
// Do not call rollback on a transaction if commit throw an exception.
void rollback(TransactionStatus status) throws TransactionException;
}


TransactionStatus represents the status of the current transaction execution. If it is a declarative transaction, the transaction status information is stored in ThreadLocal, see TransactionAspectSupport, and the current transaction status can be obtained through the static method TransactionAspectSupport#currentTransactionStatus.

AbstractPlatformTransactionManager

Abstract base class that implements Spring’s standard transaction workflow

This abstract class provides the following workflow processing:

  • Determine whether there is a transaction
  • Applied Transaction Propagation Method
  • Suspend or resume transactions
  • Check the rollback-only flag when submitting
  • Make appropriate changes to the rollback (rollback directly? Or set the rollback-only flag)
  • Call the transaction synchronizer callback method (if the synchronizer is enabled)

About the transaction synchronizer: Transaction synchronization is a generic mechanism for registering callbacks that get invoked at transaction completion time. This is mainly used internally by the data access support classes for JDBC, Hibernate, JPA, etc when running within a JTA transaction: They register resources that are opened within the transaction for closing at transaction completion time, allowing e.g. for reuse of the same Hibernate Session within the transaction. The same mechanism can also be leveraged for custom synchronization needs in an application.
The transaction synchronizer is equivalent to a transaction extension point. In the final stage of the transaction, the method of the transaction synchronizer is provided to facilitate the expansion. The TransactionSynchronization interface provides four callback methods #beforeCommit #beforeCompletion #afterCommit #afterCompletion

The transaction synchronizer is managed by TransactionSynchronizationManager, all TransactionSynchronization and Resources (such as DataSource’s Connection resource, Mybatis’ SqlSession resource) are placed in ThreadLocal , you can register, obtain resource information and TransactionSynchronization through the static method of TransactionSynchronizationManager

To inherit this class, the following abstract methods must be overridden:

  • doGetTransaction
  • doBegin
  • doCommit
  • doRollback

Other methods do not force rewriting, optional doSuspend, doResume, doSuspendSynchronization, doResumeSynchronization, doRollbackOnCommitException, doSetRollbackOnly, doCleanupAfterCompletion

Programmatic TransactionTemplate

TransactionTemplate provides us with a programmatic transaction template. When we need to call a programmatic transaction, we only need to call TransactionTemplate#execute or the interface defaultTransactionOperations#executeWithoutResult , corresponding to the cases with and without return values, respectively. Both types of methods will finally call the TransactionTemplate#execute method.

Use Cases:

@Service
class TransactionService{<!-- -->
// register somewhere
@Resource
private TransactionTemplate transactionTemplate;

@Resource
private OneMapper oneMapper;

@Resource
private TwoMapper twoMapper;

public void runSelfDefineTransaction(){<!-- -->
\t\t
transactionTemplate.setIsolationLevel(TransactionDefinition.PROPAGATION_REQUIRED);
        transactionTemplate.setTimeout(5);
        transactionTemplate.setReadOnly(false);
\t
transactionTemplate.executeWithoutResult(
                transactionStatus -> {<!-- -->
                    oneMapper. insert(...);
                    twoMapper. insert(...);
                }
        );
}
}

The source code of TransactionTemplate is as follows:

// Inherited from TransactionDefinition, configuration can be modified
public class TransactionTemplate extends DefaultTransactionDefinition
implements TransactionOperations, InitializingBean {<!-- -->
@Nullable
private PlatformTransactionManager transactionManager;
...
// The transaction execution process is converted into TransactionCallback incoming
@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {<!-- -->
...
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {<!-- -->
// Execute custom transaction operations
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {<!-- -->
// Transactional code throw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {<!-- -->
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
\t\t\t// submit
this.transactionManager.commit(status);
return result;

}

Declarative transaction

Spring declarative transactions are implemented through AOP, and interceptors are added to methods annotated with @Transactional (pay attention to the usage method, otherwise it will not take effect, such as methods must be public and avoid intra-class calls), in the interceptor Call the related methods of TransactionManager, see TransactionInterceptor.

About AOP, you can refer to Spring AOP and proxy class execution order
Since the interceptor of the transaction does not implement the Ordered interface, the annotation @Order, and the annotation @Priority, the default is the lowest priority

Declarative transactions can obtain the currently running transaction through the TransanctionAspectSupport tool class