The forty-seventh chapter of Spring's road to godhood: source code analysis of spring programmatic transactions

The main content of this article: In-depth analysis of Spring programmatic transaction source code to understand the essence of spring transactions

Before starting this article, some necessary knowledge needs to be understood first

  1. Play with JdbcTemplate
  2. Explain Spring programmatic transactions in detail
  3. Detailed explanation of Spring declarative transactions (@EnableTransactionManagement, @Transactional)
  4. Detailed explanation of 7 propagation behaviors of Spring transactions
  5. Detailed Explanation of Spring Multi-Data Source Transaction

Table of contents

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-jxSQV8tD-1684552189523)(%E6%96%B0%E5%BB%BA%E6%96%87% E6%9C%AC%E6%96%87%E6%A1%A3/1369022-20211106194316572-854186439.png)]

environment

  1. jdk1.8
  2. Spring version: 5.2.3.RELEASE
  3. mysql5.7

Review programmatic transaction usage

@Test
public void test1() throws Exception {
    
    
    //定义一个数据源
    org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/javacode2018?characterEncoding=UTF-8");
    dataSource.setUsername("root");
    dataSource.setPassword("root123");
    dataSource.setInitialSize(5);
    //定义一个JdbcTemplate,用来方便执行数据库增删改查
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
    //1.定义事务管理器,给其指定一个数据源(可以把事务管理器想象为一个人,这个人来负责事务的控制操作)
    PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
    //2.定义事务属性:TransactionDefinition,TransactionDefinition可以用来配置事务的属性信息,比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。
    TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
    //3.获取事务:调用platformTransactionManager.getTransaction开启事务操作,得到事务状态(TransactionStatus)对象
    TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
    //4.执行业务操作,下面就执行2个插入操作
    try {
    
    
        System.out.println("before:" + jdbcTemplate.queryForList("SELECT * from t_user"));
        jdbcTemplate.update("insert into t_user (name) values (?)", "test1-1");
        jdbcTemplate.update("insert into t_user (name) values (?)", "test1-2");
        //5.提交事务:platformTransactionManager.commit
        platformTransactionManager.commit(transactionStatus);
    } catch (Exception e) {
    
    
        //6.回滚事务:platformTransactionManager.rollback
        platformTransactionManager.rollback(transactionStatus);
    }
    System.out.println("after:" + jdbcTemplate.queryForList("SELECT * from t_user"));
}

programmatic transaction process

We have simplified the programmatic transaction process as follows:

1、定义事务属性信息:TransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
2、定义事务管理器:PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);
3、获取事务:TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
4、执行sql操作:比如上面通过JdbcTemplate的各种方法执行各种sql操作
5、提交事务(platformTransactionManager.commit)或者回滚事务(platformTransactionManager.rollback)

Let's analyze the above 4 steps through the source code, so that everyone can understand the principle.

1. Define transaction attribute information (TransactionDefinition)

During the process of transaction startup, some configuration information of the transaction needs to be defined, such as: transaction propagation behavior, isolation level, timeout period, whether it is a read-only transaction, transaction name, and the TransactionDefinition interface is used in spring to represent transaction definition information. Let’s take a look at the source code of the TransactionDefinition interface , there are mainly 5 information

  • Transaction Propagation Behavior
  • transaction isolation level
  • transaction timeout
  • Is it a read-only transaction
  • transaction name
public interface TransactionDefinition {
    
    

    //传播行为:REQUIRED
    int PROPAGATION_REQUIRED = 0;

    //传播行为:REQUIRED
    int PROPAGATION_SUPPORTS = 1;

    //传播行为:REQUIRED
    int PROPAGATION_MANDATORY = 2;

    //传播行为:REQUIRED
    int PROPAGATION_REQUIRES_NEW = 3;

    //传播行为:REQUIRED
    int PROPAGATION_NOT_SUPPORTED = 4;

    //传播行为:REQUIRED
    int PROPAGATION_NEVER = 5;

    //传播行为:REQUIRED
    int PROPAGATION_NESTED = 6;

    //默认隔离级别
    int ISOLATION_DEFAULT = -1;

    //隔离级别:读未提交
    int ISOLATION_READ_UNCOMMITTED = 1;

    //隔离级别:读已提交
    int ISOLATION_READ_COMMITTED = 2;

    //隔离级别:可重复读
    int ISOLATION_REPEATABLE_READ = 4;

    //隔离级别:序列化的方式
    int ISOLATION_SERIALIZABLE = 8;

    //默认超时时间
    int TIMEOUT_DEFAULT = -1;

    //返回事务传播行为,默认是REQUIRED
    default int getPropagationBehavior() {
    
    
        return PROPAGATION_REQUIRED;
    }

    //返回事务的隔离级别
    default int getIsolationLevel() {
    
    
        return ISOLATION_DEFAULT;
    }

    //返回事务超时时间(秒)
    default int getTimeout() {
    
    
        return -1;
    }

    //是否是只读事务
    default boolean isReadOnly() {
    
    
        return false;
    }

    //获取事务名称
    @Nullable
    default String getName() {
    
    
        return null;
    }

    //获取默认的事务定义信息
    static TransactionDefinition withDefaults() {
    
    
        return StaticTransactionDefinition.INSTANCE;
    }

}

There are many implementation classes of the TransactionDefinition interface. We focus on the two most used ones.

  • DefaultTransactionDefinition : A default implementation of the TransactionDefinition interface, which can usually be used in programmatic transactions
  • RuleBasedTransactionAttribute : This is used in declarative transactions. There are some dynamic matching rules for transaction rollback, which will be discussed later in declarative transactions.

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-R8zW11w3-1684552189524) (%E6%96%B0%E5%BB%BA%E6%96%87% E6%9C%AC%E6%96%87%E6%A1%A3/1369022-20211106195010236-865926796.png)]

DefaultTransactionDefinition is usually used in programmatic transactions, as follows:

DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
//设置事务传播行为
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);
//设置事务隔离级别
transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//设置是否是只读事务
transactionDefinition.setReadOnly(true);
//设置事务超时时间(s),事务超过了指定的时间还未结束,会抛异常
transactionDefinition.setTimeout(5);
//设置事务名称,这个名称可以随便设置,不过最好起个有意义的名字,在debug的过程中会输出
transactionDefinition.setName("class完整类名.方法名称");

Enter step 2 below to define the transaction manager.

2. Define the transaction manager (PlatformTransactionManager)

Transaction manager, this is a very important role, you can think of this product as a person, spring relies on this person to manage transactions, responsible for: obtaining transactions, committing transactions, rolling back transactions, and using the PlatformTransactionManager interface in Spring to represent transaction management device, there are three methods in the interface

public interface PlatformTransactionManager {
    
    

    //通过事务管理器获取一个事务,返回TransactionStatus:内部包含事务的状态信息
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;

    //根据事务的状态信息提交事务
    void commit(TransactionStatus status) throws TransactionException;

    //根据事务的状态信息回滚事务
    void rollback(TransactionStatus status) throws TransactionException;

}

PlatformTransactionManager has multiple implementation classes to deal with different environments. For example, if you use hibernate or mybatis to operate db, the transaction managers used are different. The common transaction manager implementations are as follows

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-92lixFZa-1684552189525) (%E6%96%B0%E5%BB%BA%E6%96%87% E6%9C%AC%E6%96%87%E6%A1%A3/1369022-20211106195113423-1900823506.png)]

JpaTransactionManager : If you use jpa to operate db, you need to use this manager to help you control transactions.

DataSourceTransactionManager : If you use the method of specifying the data source, such as operating the database using: JdbcTemplate, mybatis, ibatis, then you need to use this manager to help you control the transaction.

HibernateTransactionManager : If you use hibernate to operate db, then you need to use this manager to help you control transactions.

JtaTransactionManager : If you use jta in java to operate db, this is usually a distributed transaction, and you need to use this manager to control the transaction.

DataSourceTransactionManagerIn our case, JdbcTemplate is used to operate db, so this manager is used .

PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);

Next, go to step 3 and start the transaction through the transaction manager.

3. Get the transaction

In the following source code, we use a REQUIRED_NEW nested in REQUIRED to illustrate, that is, a new transaction is nested in a transaction.

3.1, getTransaction: get transaction

Open the transaction through the getTransactiongetTransaction(transactionDefinition) method of the transaction manager, and pass a TransactionDefinition parameter

TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);

The transaction manager we use is DataSourceTransactionManager, let’s take a look at the source code of DataSourceTransactionManager.getTransaction

org.springframework.jdbc.datasource.DataSourceTransactionManager

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    
    

    //事务定义信息,若传入的definition如果为空,取默认的
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

    //@3.1-1:获取事务对象
    Object transaction = doGetTransaction();
    boolean debugEnabled = logger.isDebugEnabled();

    //@3.1-2:当前是否存在事务
    if (isExistingTransaction(transaction)) {
    
    
        //@1-3:如果当前存在事务,走这里
        return handleExistingTransaction(def, transaction, debugEnabled);
    }
    // 当前没有事务,走下面的代码
    // 若事务传播级别是PROPAGATION_MANDATORY:要求必须存在事务,若当前没有事务,弹出异常
    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) {
    
    
        //事务传播行为(PROPAGATION_REQUIRED|PROPAGATION_REQUIRES_NEW|PROPAGATION_NESTED)走这里
        //@3.1-4:挂起事务
        SuspendedResourcesHolder suspendedResources = suspend(null);
        try {
    
    
            //@3.1-5:是否开启新的事务同步
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            //@3.1-6:创建事务状态对象DefaultTransactionStatus,DefaultTransactionStatus是TransactionStatus的默认实现
            DefaultTransactionStatus status = newTransactionStatus(def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            //@3.1-7:doBegin用于开始事务
            doBegin(transaction, def);
            //@3.1-8:准备事务同步
            prepareSynchronization(status, def);
            //@3.1-9:返回事务状态对象
            return status;
        } catch (RuntimeException | Error ex) {
    
    
            //@3.1-10:出现(RuntimeException|Error)恢复被挂起的事务
            resume(null, suspendedResources);
            throw ex;
        }
    } else {
    
    
        //@3.1-11:其他事务传播行为的走这里(PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER)
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
    }
}

Let's take a look at @3.1-1: doGetTransaction method, used to get the transaction object

3.2, doGetTransaction: get transaction object

org.springframework.jdbc.datasource.DataSourceTransactionManager

protected Object doGetTransaction() {
    
    
    //@3.2-1:创建数据源事务对象
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    //@3.2-2:是否支持内部事务
    txObject.setSavepointAllowed(isNestedTransactionAllowed());
    //@3.2-4:ConnectionHolder表示jdbc连接持有者,简单理解:数据的连接被丢到ConnectionHolder中了,ConnectionHolder中提供了一些方法来返回里面的连接,此处调用TransactionSynchronizationManager.getResource方法来获取ConnectionHolder对象
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
    //@3.2-5:将conHolder丢到DataSourceTransactionObject中,第二个参数表示是否是一个新的连接,明显不是的吗,新的连接需要通过datasource来获取,通过datasource获取的连接才是新的连接
    txObject.setConnectionHolder(conHolder, false);
    return txObject;
}

Let's take a look at @3.2-4the code below. This is the key point. This uses a new class TransactionSynchronizationManager:事务同步管理器. What is synchronization? In a transaction process, the called methods are executed serially in a thread, which is synchronization; a lot of ThreadLocal is used in this class to store some information related to the transaction in the thread, let’s take a look

public abstract class TransactionSynchronizationManager {
    
    

    //存储事务资源信息
    private static final ThreadLocal<Map<Object, Object>> resources =
            new NamedThreadLocal<>("Transactional resources");

    //存储事务过程中的一些回调接口(TransactionSynchronization接口,这个可以在事务的过程中给开发者提供一些回调用的)
    private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
            new NamedThreadLocal<>("Transaction synchronizations");

    //存储当前正在运行的事务的名称
    private static final ThreadLocal<String> currentTransactionName =
            new NamedThreadLocal<>("Current transaction name");

    //存储当前正在运行的事务是否是只读的
    private static final ThreadLocal<Boolean> currentTransactionReadOnly =
            new NamedThreadLocal<>("Current transaction read-only status");

    //存储当前正在运行的事务的隔离级别
    private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
            new NamedThreadLocal<>("Current transaction isolation level");

    //存储当前正在运行的事务是否是活动状态,事务启动的时候会被激活
    private static final ThreadLocal<Boolean> actualTransactionActive =
            new NamedThreadLocal<>("Actual transaction active");

    //还有很多静态方法,主要是用来操作上面这些ThreadLocal的,这里就不列出的,大家可以去看看
}

Let's look at the TransactionSynchronizationManager.getResource code

ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());

obtainDataSource() will return the datasource object in the transaction manager

protected DataSource obtainDataSource() {
    
    
    DataSource dataSource = getDataSource();
    Assert.state(dataSource != null, "No DataSource set");
    return dataSource;
}

Let's look at the source code of TransactionSynchronizationManager.getResource

public static Object getResource(Object key) {
    
    
    //通过TransactionSynchronizationUtils.unwrapResourceIfNecessary(key)获取一个actualKey,我们传入的是datasouce,实际上最后actualKey和传入的datasource是一个对象
    Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
    //调用doGetResource方法获取对应的value
    Object value = doGetResource(actualKey);
    return value;
}

The doGetResource(actualKey) method is as follows. Internally, the data ConnectionHolder object will be obtained from the ThreadLocal of resources. So far, no data has been put into the resource at all. The obtained conHolder must be null

static final ThreadLocal<Map<Object, Object>> resources = new NamedThreadLocal<>("Transactional resources");

private static Object doGetResource(Object actualKey) {
    
    
    Map<Object, Object> map = resources.get();
    if (map == null) {
    
    
        return null;
    }
    Object value = map.get(actualKey);
    return value;
}

TransactionSynchronizationManager.getResource: It can be understood as finding the ConnectionHolder object bound by transactionManager.datasource from resource ThreadLocal

At this point, the Object transaction = doGetTransaction() method is executed. Let’s go back to the getTransaction method. The first time we come in, there is no transaction in the context, so we will go to the following @3.1-4 code. There is currently no transaction, resulting in No transaction needs to be suspended, so the suspend method can be ignored first

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
        throws TransactionException {
    
    

    //事务定义信息,若传入的definition如果为空,取默认的
    TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());

    //@3.1-1:获取事务对象
    Object transaction = doGetTransaction();

    if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
            def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
    
    
        //事务传播行为(PROPAGATION_REQUIRED|PROPAGATION_REQUIRES_NEW|PROPAGATION_NESTED)走这里
        //@3.1-4:挂起事务
        SuspendedResourcesHolder suspendedResources = suspend(null);
        try {
    
    
            //@3.1-5:是否开启新的事务同步
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            //@3.1-6:创建事务状态对象DefaultTransactionStatus,DefaultTransactionStatus是TransactionStatus的默认实现
            DefaultTransactionStatus status = newTransactionStatus(
                    def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            //@3.1-7:doBegin用于开始事务
            doBegin(transaction, def);
            //@3.1-8:准备事务同步
            prepareSynchronization(status, def);
            //@3.1-9:返回事务状态对象
            return status;
        } catch (RuntimeException | Error ex) {
    
    
            //@3.1-10:出现(RuntimeException|Error)恢复被挂起的事务
            resume(null, suspendedResources);
            throw ex;
        }
    }
}

Then the following code will be executed

//@3.1-5:是否开启新的事务同步,事务同步是干嘛的,是spring在事务过程中给开发者预留的一些扩展点,稍后细说;大家先这么理解,每个新的事务newSynchronization都是true,开一个一个新的事务就会启动一个新的同步
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
//@3.1-6:创建事务状态对象DefaultTransactionStatus,DefaultTransactionStatus是TransactionStatus的默认实现
DefaultTransactionStatus status = newTransactionStatus(def, transaction, true, newSynchronization, debugEnabled, suspendedResources);
//@3.1-7:doBegin用于开始事务
doBegin(transaction, def);
//@3.1-8:准备事务同步
prepareSynchronization(status, def);
//@3.1-9:返回事务状态对象
return status;

Let’s focus on the above process @3.1-7 and @3.1-8

3.3, @3.1-7: doBegin starts the transaction

org.springframework.jdbc.datasource.DataSourceTransactionManager#doBegin

protected void doBegin(Object transaction, TransactionDefinition definition) {
    
    
    //数据源事务对象
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    //数据库连接
    Connection con = null;
    try {
    
    
        //txObject.hasConnectionHolder()用来判断txObject.connectionHolder!=null,现在肯定是null,所以txObject.hasConnectionHolder()返回false
        if (!txObject.hasConnectionHolder() ||
                txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
    
    
            //调用transactionManager.datasource.getConnection()获取一个数据库连接
            Connection newCon = obtainDataSource().getConnection();
            //将数据库连接丢到一个ConnectionHolder中,放到txObject中,注意第2个参数是true,表示第一个参数的ConnectionHolder是新创建的
            txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
        }
        //连接中启动事务同步
        txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
        //获取连接
        con = txObject.getConnectionHolder().getConnection();
        //获取隔离级别
        Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
        //设置隔离级别
        txObject.setPreviousIsolationLevel(previousIsolationLevel);
        //设置是否是只读
        txObject.setReadOnly(definition.isReadOnly());

        //判断连接是否是自动提交的,如果是自动提交的将其置为手动提交
        if (con.getAutoCommit()) {
    
    
            //在txObject中存储一下连接自动提交老的值,用于在事务执行完毕之后,还原一下Connection的autoCommit的值
            txObject.setMustRestoreAutoCommit(true);
            //设置手动提交
            con.setAutoCommit(false);
        }
        //准备事务连接
        prepareTransactionalConnection(con, definition);
        //设置事务活动开启
        txObject.getConnectionHolder().setTransactionActive(true);

        //根据事务定义信息获取事务超时时间
        int timeout = determineTimeout(definition);
        if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
    
    
            //设置连接的超时时间
            txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
        }
        //txObject中的ConnectionHolder是否是一个新的,确实是新的,所以这个地方返回true
        if (txObject.isNewConnectionHolder()) {
    
    
            //将datasource->ConnectionHolder丢到resource ThreadLocal的map中
            TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
        }
    }
}

Focus on the following code

TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());

source code

org.springframework.transaction.support.TransactionSynchronizationManager#bindResource

public static void bindResource(Object key, Object value) throws IllegalStateException {
    
    
    Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
    Map<Object, Object> map = resources.get();
    if (map == null) {
    
    
        map = new HashMap<>();
        resources.set(map);
    }
    map.put(actualKey, value);
}

After the above code is executed, datasource->ConnectionHoloder(conn) is placed in the map of resources Threadloca.

3.4, @3.1-8: prepareSynchronization prepares transaction synchronization

//@3.1-8:准备事务同步
prepareSynchronization(status, def);

The source code is as follows. Take a look. The main function of this method is that when a new transaction is started, the transaction status, isolation level, whether it is a read-only transaction, and the transaction name are thrown into various corresponding ThreadLocals in the TransactionSynchronizationManager. It is convenient to share these data in the current thread.

org.springframework.transaction.support.AbstractPlatformTransactionManager#prepareSynchronization
    
protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {
    
    
    //如果是一个新的事务,status.isNewSynchronization()将返回true
    if (status.isNewSynchronization()) {
    
    
        TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());
        TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(
                definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?
                        definition.getIsolationLevel() : null);
        TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());
        TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());
        //@3.4-1:初始化事务同步
        TransactionSynchronizationManager.initSynchronization();
    }
}

@3.4-1: Initialize transaction synchronization

org.springframework.transaction.support.TransactionSynchronizationManager

private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
   new NamedThreadLocal<>("Transaction synchronizations");

//获取同步是否启动,新事务第一次进来synchronizations.get()是null,所以这个方法返回的是false
public static boolean isSynchronizationActive() {
    
    
    return (synchronizations.get() != null);
}

//初始化事务同步,主要就是在synchronizations ThreadLocal中放一个LinkedHashSet
public static void initSynchronization() throws IllegalStateException {
    
    
    if (isSynchronizationActive()) {
    
    
        throw new IllegalStateException("Cannot activate transaction synchronization - already active");
    }
    synchronizations.set(new LinkedHashSet<>());
}

3.5 Summary

The process of obtaining transactions is over, let's take a look at some key things done in this process

1、获取db连接:从事务管理器的datasource中调用getConnection获取一个新的数据库连接,将连接置为手动提交
2、将datasource关联连接丢到ThreadLocal中:将第一步中获取到的连丢到ConnectionHolder中,然后将事务管理器的datasource->ConnectionHolder丢到了resource ThreadLocal中,这样我们可以通过datasource在ThreadLocal中获取到关联的数据库连接
3、准备事务同步:将事务的一些信息放到ThreadLocal中

4. Add, delete, modify and check in the transaction method

Take the following insert operation to see how this insert participates in the spring transaction.

jdbcTemplate.update("insert into t_user (name) values (?)", "test1-1");

In the end, it will enter the jdbctemplate#execute method, we will eliminate the useless code, and focus on the internal method of obtaining the connection below

org.springframework.jdbc.core.JdbcTemplate#execute(org.springframework.jdbc.core.PreparedStatementCreator, org.springframework.jdbc.core.PreparedStatementCallback<T>){
    
    
    //获取数据库连接
    Connection con = DataSourceUtils.getConnection(obtainDataSource());
    //通过conn执行db操作
}

obtainDataSource() will return the jdbctemplate.datasource object. Let's focus on the source code of DataSourceUtils.getConnection, and finally enter the following method

org.springframework.jdbc.datasource.DataSourceUtils#doGetConnection
    
public static Connection doGetConnection(DataSource dataSource) throws SQLException {
    
    
    //用jdbctemplate.datSource从TransactionSynchronizationManager的resouce ThreadLocal中获取对应的ConnectionHolder对象,在前面获取事务环节中,transactionManager.datasource->ConnectionHolder被丢到resouce ThreadLocal,而jdbctemplate.datSource和transactionManager.datasource是同一个对象,所以是可以获取到ConnectionHolder的,此时就会使用事务开启是的数据库连接
    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
    //conHolder不为空 && conHolder中有数据库连接对象
    if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
    
    
        //返回conHolder中的数据库连接对象
        return conHolder.getConnection();
    }

    //如果上面获取不到连接,会走这里,这里将会调用jdbctemplate.datasource.getConnection()从数据源中获取一个新的db连接
    Connection con = fetchConnection(dataSource);
    //将连接返回
    return con;
}

A conclusion can be drawn: if the final executed sql is to be controlled by the spring transaction, then the datasource object in the transaction manager must be the same as the jdbctemplate.datasource. This conclusion has been said many times in other articles, and everyone here is engaged Understand.

5. Submit the transaction

Call the commit method of the transaction manager to commit the transaction

platformTransactionManager.commit(transactionStatus);

commit source code

org.springframework.transaction.support.AbstractPlatformTransactionManager#commit

public final void commit(TransactionStatus status) throws TransactionException {
    
    
    //事务是否已经完成,此时还未完成,如果事务完成了,再来调用commit方法会报错
    if (status.isCompleted()) {
    
    
        throw new IllegalTransactionStateException(
                "Transaction is already completed - do not call commit or rollback more than once per transaction");
    }
    //事务状态
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    //defStatus.rollbackOnly是否是true,如果是true,说明事务状态被标注了需要回滚,此时走回滚逻辑
    if (defStatus.isLocalRollbackOnly()) {
    
    
        //走回滚逻辑
        processRollback(defStatus, false);
        return;
    }
    //提交事务过程
    processCommit(defStatus);
}

processCommit source code

org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    
    
    try {
    
    
        try {
    
    
            //提交之前的回调(给开发提供的扩展点)
            triggerBeforeCommit(status);
            //事务完成之前的回调(给开发提供的扩展点)
            triggerBeforeCompletion(status);
            //是否是新事务,如果是新事务,将执行提交操作,比如传播行为是REQUIRED中嵌套了一个REQUIRED,那么内部的事务就不是新的事务,外部的事务是新事务
            if (status.isNewTransaction()) {
    
    
                //@5-1:执行提交操作
                doCommit(status);
            }
        } catch (UnexpectedRollbackException ex) {
    
    
            //事务完成之后执行的回调(给开发提供的扩展点)
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
            throw ex;
        } catch (RuntimeException | Error ex) {
    
    
            //提交过程中有异常,执行回滚操作
            doRollbackOnCommitException(status, ex);
            throw ex;
        }
        try {
    
    
            //事务commit之后,执行一些回调(给开发提供的扩展点)
            triggerAfterCommit(status);
        } finally {
    
    
            //事务完成之后,执行一些回调(给开发提供的扩展点)
            triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
        }
    } finally {
    
    
        //事务执行完毕之后,执行一些清理操作
        cleanupAfterCompletion(status);
    }
}

The above method looks quite long, and it will focus on three things:

1. Extension points for development : the method starting with trigger is an extension point reserved for development. Some callbacks can be executed during transaction execution, mainly before transaction submission, after submission, before rollback, and rollback After that, some callbacks can be executed, which is what transaction synchronization needs to do. This extension point will be discussed later.

2. Execute the commit operation through the connection , corresponding to the above @5-1 code: doCommit(status);

3. Perform cleanup after completion : execute cleanupAfterCompletion(status) in finally;

Let's take a look at the doCommit(status) method . The main thing inside is to call the commit() of the connection to commit the transaction, as follows:

org.springframework.jdbc.datasource.DataSourceTransactionManager#doCommit

protected void doCommit(DefaultTransactionStatus status) {
    
    
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    //从ConnectionHolder中获取Connection
    Connection con = txObject.getConnectionHolder().getConnection();
    //执行commit,提交数据库事务
    con.commit();
}

cleanupAfterCompletion(status): cleanup operation

org.springframework.transaction.support.AbstractPlatformTransactionManager#cleanupAfterCompletion

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    
    
    //将事务状态置为已完成
    status.setCompleted();
    //是否是新的事务同步
    if (status.isNewSynchronization()) {
    
    
        //将TransactionSynchronizationManager中的那些ThreadLoca中的数据都清除,会调用ThreadLocal的remove()方法清除数据
        TransactionSynchronizationManager.clear();
    }
    //是否是新事务
    if (status.isNewTransaction()) {
    
    
        //执行清理操作
        doCleanupAfterCompletion(status.getTransaction());
    }
    //是否有被挂起的事务
    if (status.getSuspendedResources() != null) {
    
    
        Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
        //恢复被挂起的事务
        resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
    }
}

doCleanupAfterCompletion source code

org.springframework.jdbc.datasource.DataSourceTransactionManager#doCleanupAfterCompletion
    
protected void doCleanupAfterCompletion(Object transaction) {
    
    
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;

    //是否是一个新的ConnectionHolder,如果是新的事务,那么ConnectionHolder是新的
    if (txObject.isNewConnectionHolder()) {
    
    
        //将transactionManager.datasource->ConnectionHolder从resource Threadlocal中干掉
        TransactionSynchronizationManager.unbindResource(obtainDataSource());
    }
    //下面重置Connection,将Connection恢复到最原始的状态
    Connection con = txObject.getConnectionHolder().getConnection();
    try {
    
    
        if (txObject.isMustRestoreAutoCommit()) {
    
    
            //自动提交
            con.setAutoCommit(true);
        }
        //恢复connction的隔离级别、是否是只读事务
        DataSourceUtils.resetConnectionAfterTransaction(
                con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
    } catch (Throwable ex) {
    
    
        logger.debug("Could not reset JDBC Connection after transaction", ex);
    }
    //是否是新的连接
    if (txObject.isNewConnectionHolder()) {
    
    
        //释放连接,内部会调用conn.close()方法
        DataSourceUtils.releaseConnection(con, this.dataSource);
    }
    //还原ConnectionHoloder到最初的状态
    txObject.getConnectionHolder().clear();
}

To conclude, the main thing to do in the cleanup work is to release all the resources occupied by the current thread, and then resume the suspended transaction .

6. Rollback transaction

The rollback operation is similar to the submit operation, so I won’t talk about the source code, let’s take a look for yourself.

7. How to deal with the existence of affairs?

Let's look at another process. A REQUIRED_NEW is nested in REQUIRED, and then when it reaches REQUIRED_NEW, how does the code run? The general process is as follows

1. Determine whether there is a transaction in the online text

2. Suspend the current transaction

3. Open a new transaction and execute a new transaction

4. Resume suspended transactions

7.1. Determine whether there is a transaction: isExistingTransaction

It is relatively simple to judge whether there is a transaction in the online text, as follows:

org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction

protected boolean isExistingTransaction(Object transaction) {
    
    
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    //txObject.connectionHolder!=null && connectionHolder事务处于开启状态(上面我们介绍过在doBegin开启事务的时候connectionHolder.transactionActive会被置为true)
    return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}

7.2. If there is a current transaction

Let's take a look at how to get the transaction, if there is a transaction

org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
    
    
    //获取事务
    Object transaction = doGetTransaction();

    //是否存在事务
    if (isExistingTransaction(transaction)) {
    
    
        //存在事务会走这里
        return handleExistingTransaction(def, transaction, debugEnabled);
    }
}

There is currently a transaction, and then it will enter the handleExistingTransaction method

org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction

private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException {
    
    
    //当前有事务,被嵌套的事务传播行为是PROPAGATION_NEVER,抛出异常
    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
    
    
        throw new IllegalTransactionStateException(
                "Existing transaction found for transaction marked with propagation 'never'");
    }

    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
    
    
        //当前有事务,被嵌套的事务传播行为是PROPAGATION_NOT_SUPPORTED,那么将先调用suspend将当前事务挂起,然后以无事务的方式运行被嵌套的事务
        //挂起当前事务
        Object suspendedResources = suspend(transaction);
        boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
        //以无事务的方式运行
        return prepareTransactionStatus(
                definition, null, false, newSynchronization, debugEnabled, suspendedResources);
    }

    if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
    
    
        //被嵌套的事务传播行为是PROPAGATION_REQUIRES_NEW,那么会先挂起当前事务,然后会重新开启一个新的事务
        //挂起当前事务
        SuspendedResourcesHolder suspendedResources = suspend(transaction);
        try {
    
    
            //下面的过程我们就不在再介绍了,之前有介绍过
            boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
            DefaultTransactionStatus status = newTransactionStatus(
                    definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
            doBegin(transaction, definition);
            prepareSynchronization(status, definition);
            return status;
        } catch (RuntimeException | Error beginEx) {
    
    
            resumeAfterBeginException(transaction, suspendedResources, beginEx);
            throw beginEx;
        }
    }
    //其他的传播行为走下面。。。,暂时省略了
}

The following focuses on transaction suspension and transaction recovery operations.

7.3. Transaction suspension: suspend

Transaction suspension calls the suspend method of the transaction manager, the source code is as follows, the main thing to do: save all the information in the current transaction to the SuspendedResourcesHolder object, which is equivalent to a snapshot of the transaction, which will be used when restoring later; and then clean up the transaction site , mainly to kill a bunch of transaction data stored in ThreadLocal.

org.springframework.transaction.support.AbstractPlatformTransactionManager#suspend

protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
    
    
    //当前事务同步是否被激活,如果是新事务,这个返回的是true
    if (TransactionSynchronizationManager.isSynchronizationActive()) {
    
    
        //挂起事务同步,这个地方会可以通过TransactionSynchronization接口给开发者提供了扩展点,稍后我们会单独介绍TransactionSynchronization接口,这个接口专门用来在事务执行过程中做回调的
        List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
        try {
    
    
            Object suspendedResources = null;
            if (transaction != null) {
    
    
                //@1:获取挂起的资源
                suspendedResources = doSuspend(transaction);
            }
            //下面就是获取当前事务的各种信息(name,readyOnly,事务隔离级别,是否被激活)
            String name = TransactionSynchronizationManager.getCurrentTransactionName();
            TransactionSynchronizationManager.setCurrentTransactionName(null);
            boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
            Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
            TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
            boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
            TransactionSynchronizationManager.setActualTransactionActive(false);
            return new SuspendedResourcesHolder(
                    suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
        }
    }
}

Let's take a look at @1:doSuspend(transaction)the source code. The main thing is to unbind datasource->connectionHolder from resource ThreadLocal, and then return connectionHolder. The following method actually returns the connectionHolder object

org.springframework.jdbc.datasource.DataSourceTransactionManager#doSuspend

protected Object doSuspend(Object transaction) {
    
    
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
    //将connectionHolder置为null
    txObject.setConnectionHolder(null);
    //将datasource->connectionHolder从resource ThreadLocal中解绑,并返回被解绑的connectionHolder对象
    return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}

At this point, the current transaction is suspended, and then a new transaction is started. The process of the new transaction has been introduced above. Let's look at the recovery process of the transaction.

7.4, transaction recovery: resume

Transaction suspension calls the resume method of the transaction manager. The source code is as follows. The main thing to do is to resume the suspended transaction through the SuspendedResourcesHolder object. The SuspendedResourcesHolder object stores all the information of the suspended transaction, so you can pass this object to resume transactions.

org.springframework.transaction.support.AbstractPlatformTransactionManager#resume

protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)
        throws TransactionException {
    
    
    if (resourcesHolder != null) {
    
    
        Object suspendedResources = resourcesHolder.suspendedResources;
        if (suspendedResources != null) {
    
    
            //恢复被挂起的资源,也就是将datasource->connectionHolder绑定到resource ThreadLocal中
            doResume(transaction, suspendedResources);
        }
        List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations;
        //下面就是将数据恢复到各种ThreadLocal中
        if (suspendedSynchronizations != null) {
    
    
            TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive);
            TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel);
            TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly);
            TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name);
            //恢复事务同步(将事务扩展点恢复)
            doResumeSynchronization(suspendedSynchronizations);
        }
    }
}

8. Callback interface during transaction execution: TransactionSynchronization

8.1. Function

During the running of spring transactions, some extension points are reserved for developers, and some methods in the extension points will be called back at different stages of transaction execution.

For example, if we want to do some transactions before transaction commit, after commit, before rollback, and after rollback, we can do it through extension points.

8.2. Usage of extension points

1. Define the transaction TransactionSynchronization object

The methods in the TransactionSynchronization interface will be automatically called back during the execution of the spring transaction

public interface TransactionSynchronization extends Flushable {
    
    

    //提交状态
    int STATUS_COMMITTED = 0;

    //回滚状态
    int STATUS_ROLLED_BACK = 1;

    //状态未知,比如事务提交或者回滚的过程中发生了异常,那么事务的状态是未知的
    int STATUS_UNKNOWN = 2;

    //事务被挂起的时候会调用被挂起事务中所有TransactionSynchronization的resume方法
    default void suspend() {
    
    
    }

    //事务恢复的过程中会调用被恢复的事务中所有TransactionSynchronization的resume方法
    default void resume() {
    
    
    }

    //清理操作
    @Override
    default void flush() {
    
    
    }

    //事务提交之前调用
    default void beforeCommit(boolean readOnly) {
    
    
    }

    //事务提交或者回滚之前调用
    default void beforeCompletion() {
    
    
    }

    //事务commit之后调用
    default void afterCommit() {
    
    
    }

    //事务完成之后调用
    default void afterCompletion(int status) {
    
    
    }

}
2. Register TransactionSynchronization into the current transaction

Register the transaction extension point TransactionSynchronization into the current transaction through the following static method

TransactionSynchronizationManager.registerSynchronization(transactionSynchronization)

Look at the source code, it's very simple, throw it into ThreadLocal

private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
   new NamedThreadLocal<>("Transaction synchronizations");

public static void registerSynchronization(TransactionSynchronization synchronization)
   throws IllegalStateException {
    
    
    Set<TransactionSynchronization> synchs = synchronizations.get();
    if (synchs == null) {
    
    
        throw new IllegalStateException("Transaction synchronization is not active");
    }
    synchs.add(synchronization);
}

When there are multiple TransactionSynchronizations, the order can be specified, and the org.springframework.core.Ordered interface can be implemented to specify the order. The order is called from the small to the large. TransactionSynchronization has a default adapter TransactionSynchronizationAdapter, which implements the Ordered interface, so , if we want to use it, use the TransactionSynchronizationAdapter class directly.

3. Call back the method in the extension point TransactionSynchronization

The method in TransactionSynchronization is automatically called by the spring transaction manager. As mentioned in this article, the transaction manager will call the method at the beginning of the trigger in many places during the process of transaction submission or transaction rollback. This trigger method will traverse internally. The transactionSynchronization list in the current transaction, and then call some specified methods inside the transactionSynchronization.

Take the source code of transaction submission as an example, let’s take a look

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    
    
    triggerBeforeCommit(status);
    triggerBeforeCompletion(status);
    //....其他代码省略
}

triggerBeforeCommit(status) source code

protected final void triggerBeforeCommit(DefaultTransactionStatus status) {
    
    
    if (status.isNewSynchronization()) {
    
    
        TransactionSynchronizationUtils.triggerBeforeCommit(status.isReadOnly());
    }
}

TransactionSynchronizationUtils.triggerBeforeCommit 源码

public static void triggerBeforeCommit(boolean readOnly) {
    
    
    for (TransactionSynchronization synchronization : TransactionSynchronizationManager.getSynchronizations()) {
    
    
        synchronization.beforeCommit(readOnly);
    }
}

8.3. Here is a case

1. Execute SQL
DROP DATABASE IF EXISTS javacode2018;
CREATE DATABASE if NOT EXISTS javacode2018;

USE javacode2018;
DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user(
  id int PRIMARY KEY AUTO_INCREMENT,
  name varchar(256) NOT NULL DEFAULT '' COMMENT '姓名'
);
2. Case code

The code is relatively simple, not much to explain, run the test method m0

package com.javacode2018.tx.demo9;

import org.junit.Before;
import org.junit.Test;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * 公众号:路人甲java,工作10年的前阿里P7,所有文章以系列的方式呈现,带领大家成为java高手,
 * 目前已出:java高并发系列、mysq|高手系列、Maven高手系列、mybatis系列、spring系列,
 * 正在连载springcloud系列,欢迎关注!
 */
public class Demo9Test {
    
    
    JdbcTemplate jdbcTemplate;
    PlatformTransactionManager platformTransactionManager;

    @Before
    public void before() {
    
    
        //定义一个数据源
        org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/javacode2018?characterEncoding=UTF-8");
        dataSource.setUsername("root");
        dataSource.setPassword("root123");
        dataSource.setInitialSize(5);
        //定义一个JdbcTemplate,用来方便执行数据库增删改查
        this.jdbcTemplate = new JdbcTemplate(dataSource);
        this.platformTransactionManager = new DataSourceTransactionManager(dataSource);
        this.jdbcTemplate.update("truncate table t_user");
    }

    @Test
    public void m0() throws Exception {
    
    
        System.out.println("PROPAGATION_REQUIRED start");
        //2.定义事务属性:TransactionDefinition,TransactionDefinition可以用来配置事务的属性信息,比如事务隔离级别、事务超时时间、事务传播方式、是否是只读事务等等。
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRED);
        //3.开启事务:调用platformTransactionManager.getTransaction开启事务操作,得到事务状态(TransactionStatus)对象
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
        this.addSynchronization("ts-1", 2);
        this.addSynchronization("ts-2", 1);
        //4.执行业务操作,下面就执行2个插入操作
        jdbcTemplate.update("insert into t_user (name) values (?)", "test1-1");
        jdbcTemplate.update("insert into t_user (name) values (?)", "test1-2");
        this.m1();
        //5.提交事务:platformTransactionManager.commit
        System.out.println("PROPAGATION_REQUIRED 准备commit");
        platformTransactionManager.commit(transactionStatus);
        System.out.println("PROPAGATION_REQUIRED commit完毕");

        System.out.println("after:" + jdbcTemplate.queryForList("SELECT * from t_user"));
    }

    public void m1() {
    
    
        System.out.println("PROPAGATION_REQUIRES_NEW start");
        TransactionDefinition transactionDefinition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
        jdbcTemplate.update("insert into t_user (name) values (?)", "test2-1");
        jdbcTemplate.update("insert into t_user (name) values (?)", "test2-2");
        this.addSynchronization("ts-3", 2);
        this.addSynchronization("ts-4", 1);
        System.out.println("PROPAGATION_REQUIRES_NEW 准备commit");
        platformTransactionManager.commit(transactionStatus);
        System.out.println("PROPAGATION_REQUIRES_NEW commit完毕");
    }

    public void addSynchronization(final String name, final int order) {
    
    
        if (TransactionSynchronizationManager.isSynchronizationActive()) {
    
    
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
    
    
                @Override
                public int getOrder() {
    
    
                    return order;
                }

                @Override
                public void suspend() {
    
    
                    System.out.println(name + ":suspend");
                }

                @Override
                public void resume() {
    
    
                    System.out.println(name + ":resume");
                }

                @Override
                public void flush() {
    
    
                    System.out.println(name + ":flush");
                }

                @Override
                public void beforeCommit(boolean readOnly) {
    
    
                    System.out.println(name + ":beforeCommit:" + readOnly);
                }

                @Override
                public void beforeCompletion() {
    
    
                    System.out.println(name + ":beforeCompletion");
                }

                @Override
                public void afterCommit() {
    
    
                    System.out.println(name + ":afterCommit");
                }

                @Override
                public void afterCompletion(int status) {
    
    
                    System.out.println(name + ":afterCompletion:" + status);
                }
            });
        }
    }

}
3. Output
PROPAGATION_REQUIRED start
PROPAGATION_REQUIRES_NEW start
ts-2:suspend
ts-1:suspend
PROPAGATION_REQUIRES_NEW 准备commit
ts-4:beforeCommit:false
ts-3:beforeCommit:false
ts-4:beforeCompletion
ts-3:beforeCompletion
ts-4:afterCommit
ts-3:afterCommit
ts-4:afterCompletion:0
ts-3:afterCompletion:0
ts-2:resume
ts-1:resume
PROPAGATION_REQUIRES_NEW commit完毕
PROPAGATION_REQUIRED 准备commit
ts-2:beforeCommit:false
ts-1:beforeCommit:false
ts-2:beforeCompletion
ts-1:beforeCompletion
ts-2:afterCommit
ts-1:afterCommit
ts-2:afterCompletion:0
ts-1:afterCompletion:0
PROPAGATION_REQUIRED commit完毕
after:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=test2-1}, {id=4, name=test2-2}]

Output the source code of the matching case for everyone to understand.

in conclusion

Today's content is quite long, thank you for your hard work, but I believe that if you have a thorough understanding of spring affairs, you will gain a lot, come on!

If you have any questions about transactions, please leave me a message. The next article will analyze the source code of declarative transactions, so stay tuned! ! **

Case source code

git地址:
https://gitee.com/javacode2018/spring-series

本文案例对应源码:
    spring-series\lesson-002-tx\src\main\java\com\javacode2018\tx\demo9

Passerby A All java case codes will be put on this in the future, everyone watch it, you can continue to pay attention to the dynamics.

public void afterCompletion(int status) {
System.out.println(name + “:afterCompletion:” + status);
}
});
}
}

}


##### 3、输出

PROPAGATION_REQUIRED start
PROPAGATION_REQUIRES_NEW start
ts-2:suspend
ts-1:suspend
PROPAGATION_REQUIRES_NEW 准备commit
ts-4:beforeCommit:false
ts-3:beforeCommit:false
ts-4:beforeCompletion
ts-3:beforeCompletion
ts-4:afterCommit
ts-3:afterCommit
ts-4:afterCompletion:0
ts-3:afterCompletion:0
ts-2:resume
ts-1:resume
PROPAGATION_REQUIRES_NEW commit完毕
PROPAGATION_REQUIRED 准备commit
ts-2:beforeCommit:false
ts-1:beforeCommit:false
ts-2:beforeCompletion
ts-1:beforeCompletion
ts-2:afterCommit
ts-1:afterCommit
ts-2:afterCompletion:0
ts-1:afterCompletion:0
PROPAGATION_REQUIRED commit完毕
after:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=test2-1}, {id=4, name=test2-2}]


输出配合案例源码,大家理解一下。

### 总结一下

**今天的内容挺长的,辛苦大家了,不过我相信spring事务这块吃透了,会让你收获很多,加油!**

**事务方面有任何问题的欢迎给我留言,下篇文章将解析声明式事务的源码,敬请期待!!****

### 案例源码

Git address:
https://gitee.com/javacode2018/spring-series

The source code corresponding to the case in this article:
spring-series\lesson-002-tx\src\main\java\com\javacode2018\tx\demo9


**路人甲java所有案例代码以后都会放到这个上面,大家watch一下,可以持续关注动态。**

来源:https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648937564&idx=2&sn=549f841b7935c6f5f98957e4d443f893&scene=21#wechat_redirect

Guess you like

Origin blog.csdn.net/china_coding/article/details/130779283