Spring の神への道の第 47 章: Spring のプログラム トランザクションのソース コード分析

この記事の主な内容: Spring トランザクションの本質を理解するための Spring プログラム トランザクション ソース コードの詳細な分析

この記事を始める前に、いくつかの必要な知識を理解する必要があります。

  1. JdbcTemplate で遊ぶ
  2. Spring のプログラムによるトランザクションを詳しく説明する
  3. Springの宣言型トランザクション(@EnableTransactionManagement、@Transactional)の詳細説明
  4. Springトランザクションの7つの伝播動作を詳しく解説
  5. Springマルチデータソーストランザクションの詳細説明

目次

[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (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)]

環境

  1. jdk1.8
  2. 春のバージョン: 5.2.3.RELEASE
  3. mysql5.7

プログラムによるトランザクションの使用状況を確認する

@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"));
}

プログラムによるトランザクションプロセス

プログラムによるトランザクション プロセスを次のように簡素化しました。

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)

誰もが原理を理解できるように、ソース コードを通して上記の 4 つのステップを分析してみましょう。

1. トランザクション属性情報の定義(TransactionDefinition)

トランザクションの開始プロセス中に、トランザクションの伝播動作、分離レベル、タイムアウト期間、読み取り専用トランザクションかどうか、トランザクション名、トランザクション定義インターフェイスが使用されるなど、トランザクションのいくつかの構成情報を定義する必要があります。 Spring はトランザクション定義情報を表します。TransactionDefinition インターフェイスのソース コードを見てみましょう。主に 5 つの情報があります。

  • トランザクションの伝播動作
  • トランザクション分離レベル
  • トランザクションタイムアウト
  • 読み取り専用トランザクションですか
  • トランザクション名
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;
    }

}

TransactionDefinition インターフェイスの実装クラスは多数ありますが、最もよく使用される 2 つのクラスに焦点を当てます。

  • DefaultTransactionDefinition : TransactionDefinition インターフェースのデフォルト実装。通常はプログラムによるトランザクションで使用できます。
  • RuleBasedTransactionAttribute : これは宣言的トランザクションで使用されます。トランザクションのロールバックには動的一致ルールがいくつかありますが、これについては宣言的トランザクションで後述します。

[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (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 は通常、次のようにプログラム トランザクションで使用されます。

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完整类名.方法名称");

以下のステップ 2 を入力して、トランザクション マネージャーを定義します。

2. トランザクション マネージャー (PlatformTransactionManager) を定義します。

トランザクション マネージャー、これは非常に重要な役割です。この製品を人間として考えることができます。Spring はトランザクションの管理をこの人間に依存しており、トランザクションの取得、トランザクションのコミット、トランザクションのロールバック、および Spring の PlatformTransactionManager インターフェイスの使用を担当しますトランザクション管理デバイスを表し、インターフェースには 3 つのメソッドがあります

public interface PlatformTransactionManager {
    
    

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

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

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

}

PlatformTransactionManager は環境の違いに対応するために複数の実装クラスを持っています 例えば、db の操作に Hibernate や mybatis を使用する場合、使用するトランザクション マネージャが異なります。一般的なトランザクション マネージャの実装は次のとおりです。

[外部リンク画像の転送に失敗しました。ソース サイトには盗難防止リンク メカニズムがある可能性があります。画像を保存して直接アップロードすることをお勧めします (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 : jpa を使用して db を操作する場合、トランザクションの制御を支援するためにこのマネージャーを使用する必要があります。

DataSourceTransactionManager : JdbcTemplate、mybatis、ibatis を使用してデータベースを操作するなど、データ ソースを指定する方法を使用する場合は、トランザクションの制御を支援するためにこのマネージャーを使用する必要があります。

HibernateTransactionManager : Hibernate を使用してデータベースを操作する場合、トランザクションの制御を支援するためにこのマネージャーを使用する必要があります。

JtaTransactionManager : Java で jta を使用して db を操作する場合、これは通常分散トランザクションになるため、トランザクションを制御するにはこのマネージャーを使用する必要があります。

DataSourceTransactionManager今回の場合、dbの操作にJdbcTemplateを使用するため、このマネージャーを使用します。

PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);

次に、ステップ 3 に進み、トランザクション マネージャーを通じてトランザクションを開始します。

3. トランザクションを取得する

次のソース コードでは、REQUIRED にネストされた REQUIRED_NEW を使用して、新しいトランザクションがトランザクション内にネストされていることを示します。

3.1、getTransaction: トランザクションを取得します。

トランザクション マネージャーの getTransactiongetTransaction(transactionDefinition) メソッドを通じてトランザクションを開き、TransactionDefinition パラメーターを渡します。

TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);

使用するトランザクション マネージャーは DataSourceTransactionManager です。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);
    }
}

@3.1-1: doGetTransaction メソッドを見てみましょう。トランザクション オブジェクトを取得するために使用されます。

3.2、doGetTransaction: トランザクション オブジェクトを取得する

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;
}

@3.2-4以下のコードを見てみましょう. これが重要なポイントです. これは新しいクラスを使用していますTransactionSynchronizationManager:事务同步管理器. 同期とは何ですか? トランザクション プロセスでは、呼び出されたメソッドがスレッド内でシリアルに実行されます (これが同期です)。スレッド内のトランザクションに関連する情報を保存するために、このクラスでは多くの ThreadLocal が使用されます。見てみましょう。

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的,这里就不列出的,大家可以去看看
}

TransactionSynchronizationManager.getResource コードを見てみましょう

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

getDataSource() はトランザクション マネージャーのデータソース オブジェクトを返します。

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

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;
}

doGetResource(actualKey) メソッドは次のとおりです。内部的には、データ ConnectionHolder オブジェクトはリソースの ThreadLocal から取得されます。これまでのところ、リソースにはデータはまったく入力されていません。取得された conHolder は 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: リソース ThreadLocal から、transactionManager.datasource によってバインドされた ConnectionHolder オブジェクトを見つけることとして理解できます。

この時点で、Object トランザクション = doGetTransaction() メソッドが実行されます。getTransaction メソッドに戻りましょう。初めてアクセスしたときは、コンテキストにトランザクションがないため、次の @3.1-4 コードに進みます。現在トランザクションが存在しないため、一時停止する必要のあるトランザクションはありません。そのため、最初は一時停止メソッドを無視できます。

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;
        }
    }
}

次に、次のコードが実行されます

//@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;

上記のプロセス @3.1-7 と @3.1-8 に注目してみましょう。

3.3、@3.1-7: doBegin がトランザクションを開始します

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());
        }
    }
}

次のコードに注目してください

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

ソースコード

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);
}

上記のコードが実行されると、datasource->ConnectionHoloder(conn) がリソース Threadloca のマップに配置されます。

3.4、@3.1-8: prepareSynchronization はトランザクション同期を準備します

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

このメソッドの主な機能は、新しいトランザクションが開始されると、トランザクションのステータス、分離レベル、読み取り専用トランザクションかどうか、およびトランザクション名がさまざまなトランザクションにスローされることです。 TransactionSynchronizationManager 内の対応する ThreadLocals これらのデータを現在のスレッドで共有すると便利です。

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: トランザクション同期の初期化

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 概要

トランザクションを取得するプロセスは終了しました。このプロセスで行われるいくつかの重要なことを見てみましょう。

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

4. トランザクションメソッドの追加、削除、変更、チェックイン

次の挿入操作を実行して、この挿入が Spring トランザクションにどのように参加するかを確認します。

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

最終的には jdbctemplate#execute メソッドに入り、無駄なコードを削除し、以下の接続を取得する内部メソッドに焦点を当てます。

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

getDataSource() は jdbctemplate.datasource オブジェクトを返します。DataSourceUtils.getConnection のソース コードに注目して、最後に次のメソッドを入力します。

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;
}

最終的に実行される SQL が Spring トランザクションによって制御される場合、トランザクション マネージャーのデータソース オブジェクトは jdbctemplate.datasource と同じである必要があるという結論が得られます。この結論は他の記事で何度も述べられています。ここにいる全員が熱心に取り組んでいます。

5. トランザクションを送信する

トランザクションマネージャーの commit メソッドを呼び出してトランザクションをコミットします。

platformTransactionManager.commit(transactionStatus);

ソースコードをコミットする

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);
}

processソースコードをコミットする

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);
    }
}

上記の方法は非常に長くなりますが、次の 3 つの点に焦点を当てます

1. 開発用拡張ポイント:triggerで始まるメソッドは開発用に予約された拡張ポイントです 一部のコールバックはトランザクション実行中、主にトランザクション投入前、投入後、ロールバック前、ロールバック後に実行可能ですこれは、トランザクション同期で行う必要があることです。この拡張ポイントについては後で説明します。

2.上記の @5-1 コードに対応して、接続を通じてコミット操作を実行します。 doCommit(status);

3. 完了後にクリーンアップを実行します。最後に cleanupAfterCompletion(status) を実行します。

doCommit(status) メソッドを見てみましょう。内部の主なことは、次のように、接続の commit() を呼び出してトランザクションをコミットすることです。

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): クリーンアップ操作

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 ソース コード

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();
}

結論として、クリーンアップ作業で行う主な作業は、現在のスレッドが占有しているすべてのリソースを解放し、中断されたトランザクションを再開することです

6. トランザクションのロールバック

ロールバック操作は送信操作と似ているので、ソース コードについては説明しません。自分で見てみましょう。

7.不倫の存在にどう対処するか?

別のプロセスを見てみましょう。REQUIRED_NEW は REQUIRED にネストされており、REQUIRED_NEW に到達すると、コードはどのように実行されるでしょうか。一般的なプロセスは次のとおりです

1. オンラインテキストにトランザクションがあるかどうかを判断します

2. 現在のトランザクションを一時停止します

3. 新しいトランザクションを開き、新しいトランザクションを実行します

4. 中断された取引を再開する

7.1. トランザクションが存在するかどうかを確認する: isExistingTransaction

オンラインテキストにトランザクションがあるかどうかは、次のように比較的簡単に判断できます。

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. 現在のトランザクションがある場合

トランザクションがある場合、トランザクションを取得する方法を見てみましょう。

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);
    }
}

現在トランザクションがあり、handleExistingTransaction メソッドに入ります。

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;
        }
    }
    //其他的传播行为走下面。。。,暂时省略了
}

以下では、トランザクションの一時停止とトランザクションの回復の操作に焦点を当てます。

7.3. トランザクションの一時停止: 一時停止

トランザクションの一時停止は、トランザクション マネージャーの一時停止メソッドを呼び出します。ソース コードは次のとおりです。主に行うことは、現在のトランザクションのすべての情報を SuspendedResourcesHolder オブジェクトに保存することです。これはトランザクションのスナップショットに相当します。後で復元するときに使用され、主に 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);
        }
    }
}

@1:doSuspend(transaction)ソース コードを見てみましょう。主なことは、リソース ThreadLocal から datasource->connectionHolder のバインドを解除し、connectionHolder を返すことです。次のメソッドは実際に connectionHolder オブジェクトを返します

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());
}

この時点で、現在のトランザクションは一時停止され、その後、新しいトランザクションが開始されます。新しいトランザクションのプロセスは上で紹介しましたが、トランザクションの回復プロセスを見てみましょう。

7.4、トランザクションの回復: 再開

トランザクションの一時停止は、トランザクション マネージャーの再開メソッドを呼び出します。ソース コードは次のとおりです。主に行うことは、SuspendedResourcesHolder オブジェクトを通じて一時停止されたトランザクションを再開することです。SuspendedResourcesHolder オブジェクトには、一時停止されたトランザクションのすべての情報が保存されているため、このオブジェクトを使用してトランザクションを再開します。

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. トランザクション実行時のコールバックインターフェース: TransactionSynchronization

8.1. 機能

Spring トランザクションの実行中、一部の拡張ポイントは開発者用に予約されており、拡張ポイント内の一部のメソッドはトランザクション実行のさまざまな段階でコールバックされます。

たとえば、トランザクションのコミット前、コミット後、ロールバック前、ロールバック後にいくつかのトランザクションを実行したい場合、拡張ポイントを使用して実行できます。

8.2. 拡張ポイントの使用法

1. トランザクション TransactionSynchronization オブジェクトを定義します。

TransactionSynchronization インターフェイスのメソッドは、Spring トランザクションの実行中に自動的にコールバックされます。

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. TransactionSynchronization を現在のトランザクションに登録します

次の静的メソッドを使用して、トランザクション拡張ポイント TransactionSynchronization を現在のトランザクションに登録します。

TransactionSynchronizationManager.registerSynchronization(transactionSynchronization)

ソース コードを見てください。非常に単純です。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);
}

複数の TransactionSynchronization がある場合、順序を指定でき、順序を指定するために org.springframework.core.Ordered インターフェースを実装できます。順序は小さいものから大きいものへ呼び出されます。TransactionSynchronization にはデフォルトのアダプター TransactionSynchronizationAdapter があり、これを実装します。 Ordered インターフェイスなので、これを使用したい場合は、TransactionSynchronizationAdapter クラスを直接使用します。

3. 拡張ポイント TransactionSynchronization のメソッドをコールバックします。

TransactionSynchronization のメソッドは、Spring トランザクション マネージャーによって自動的に呼び出されます。この記事で説明したように、トランザクション マネージャーは、トランザクションの送信またはトランザクションのロールバックのプロセス中に、さまざまな場所でトリガーの先頭でメソッドを呼び出します。このトリガー メソッドはトラバースします。現在のトランザクション内のtransactionSynchronizationリストを参照し、transactionSynchronization内で指定されたメソッドをいくつか呼び出します。

トランザクション送信のソースコードを例として見てみましょう

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

triggerBeforeCommit(ステータス)のソースコード

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. これが事例です

1. 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. ケースコード

コードは比較的単純で、あまり説明する必要はありません。テスト メソッド 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. 出力
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}]

一致したケースのソースコードを誰でも理解できるように出力します。

結論は

今日の内容はかなり長くなってしまいました、お疲れ様でしたが、春の事情をしっかり理解していれば得るものも大きいと思いますので、さあ!

トランザクションについて質問がある場合は、メッセージを残してください。次の記事では、宣言的トランザクションのソース コードを分析しますので、お楽しみに! **

ケースのソースコード

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

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

通行人 A 今後、すべての Java ケース コードがこれに載せられる予定です。皆さんはそれを見て、引き続きダイナミクスに注目してください。

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 準備完了
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 アドレス:
https://gitee.com/javacode2018/spring-series

この記事のケースに対応するソースコード:
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

おすすめ

転載: blog.csdn.net/china_coding/article/details/130779283