Le quarante-septième chapitre de Spring's road to godhood : analyse du code source des transactions programmatiques du printemps

Le contenu principal de cet article : Analyse approfondie du code source des transactions programmatiques Spring pour comprendre l'essence des transactions Spring

Avant de commencer cet article, certaines connaissances nécessaires doivent d'abord être comprises

  1. Jouer avec JdbcTemplate
  2. Expliquer en détail les transactions programmatiques de Spring
  3. Explication détaillée des transactions déclaratives Spring (@EnableTransactionManagement, @Transactional)
  4. Explication détaillée des 7 comportements de propagation des transactions Spring
  5. Explication détaillée de la transaction Spring Multi-Data Source

Table des matières

[Le transfert d'image du lien externe a échoué, le site source peut avoir un mécanisme de lien antivol, il est recommandé d'enregistrer l'image et de la télécharger directement (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)]

environnement

  1. jdk1.8
  2. Version printemps : 5.2.3.RELEASE
  3. mysql5.7

Examiner l'utilisation des transactions programmatiques

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

processus de transaction programmatique

Nous avons simplifié le processus de transaction programmatique comme suit :

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)

Analysons les 4 étapes ci-dessus à travers le code source, afin que chacun puisse comprendre le principe.

1. Définir les informations d'attribut de transaction (TransactionDefinition)

Pendant le processus de démarrage de la transaction, certaines informations de configuration de la transaction doivent être définies, telles que : le comportement de propagation de la transaction, le niveau d'isolement, le délai d'expiration, s'il s'agit d'une transaction en lecture seule, le nom de la transaction et l'interface TransactionDefinition utilisée dans ressort pour représenter les informations de définition de transaction. Examinons le code source de l' interface TransactionDefinition , il y a principalement 5 informations

  • Comportement de propagation des transactions
  • niveau d'isolement des transactions
  • délai d'attente des transactions
  • Est-ce une transaction en lecture seule
  • nom de l'opération
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;
    }

}

Il existe de nombreuses classes d'implémentation de l'interface TransactionDefinition, nous nous concentrons sur les deux plus utilisées.

  • DefaultTransactionDefinition : Une implémentation par défaut de l'interface TransactionDefinition, qui peut généralement être utilisée dans les transactions programmatiques
  • RuleBasedTransactionAttribute : utilisé dans les transactions déclaratives. Il existe des règles de correspondance dynamiques pour l'annulation des transactions, qui seront abordées ultérieurement dans les transactions déclaratives.

[Le transfert d'image du lien externe a échoué, le site source peut avoir un mécanisme de lien antivol, il est recommandé d'enregistrer l'image et de la télécharger directement (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 est généralement utilisé dans les transactions programmatiques, comme suit :

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

Saisissez l'étape 2 ci-dessous pour définir le gestionnaire de transactions.

2. Définir le gestionnaire de transactions (PlatformTransactionManager)

Gestionnaire de transactions, il s'agit d'un rôle très important, vous pouvez considérer ce produit comme une personne, Spring s'appuie sur cette personne pour gérer les transactions, responsable de : l'obtention des transactions, la validation des transactions, l'annulation des transactions et l'utilisation de l'interface PlatformTransactionManager dans Spring pour représentent un dispositif de gestion des transactions, il existe trois méthodes dans l'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 a plusieurs classes d'implémentation pour gérer différents environnements. Par exemple, si vous utilisez hibernate ou mybatis pour faire fonctionner la base de données, les gestionnaires de transactions utilisés sont différents. Les implémentations courantes des gestionnaires de transactions sont les suivantes

[Le transfert d'image du lien externe a échoué, le site source peut avoir un mécanisme de lien antivol, il est recommandé d'enregistrer l'image et de la télécharger directement (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 : Si vous utilisez jpa pour faire fonctionner la base de données, vous devez utiliser ce gestionnaire pour vous aider à contrôler les transactions.

DataSourceTransactionManager : si vous utilisez la méthode de spécification de la source de données, telle que l'exploitation de la base de données à l'aide de : JdbcTemplate, mybatis, ibatis, vous devez utiliser ce gestionnaire pour vous aider à contrôler la transaction.

HibernateTransactionManager : Si vous utilisez hibernate pour faire fonctionner la base de données, vous devez utiliser ce gestionnaire pour vous aider à contrôler les transactions.

JtaTransactionManager : Si vous utilisez jta en Java pour faire fonctionner la base de données, il s'agit généralement d'une transaction distribuée et vous devez utiliser ce gestionnaire pour contrôler la transaction.

DataSourceTransactionManagerDans notre cas, JdbcTemplate est utilisé pour faire fonctionner db, donc ce gestionnaire est utilisé .

PlatformTransactionManager platformTransactionManager = new DataSourceTransactionManager(dataSource);

Ensuite, passez à l'étape 3 et démarrez la transaction via le gestionnaire de transactions.

3. Obtenez la transaction

Dans le code source suivant, nous utilisons un REQUIRED_NEW imbriqué dans REQUIRED pour illustrer, c'est-à-dire qu'une nouvelle transaction est imbriquée dans une transaction.

3.1, getTransaction : obtenir une transaction

Ouvrez la transaction via la méthode getTransactiongetTransaction(transactionDefinition) du gestionnaire de transactions et transmettez un paramètre TransactionDefinition

TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);

Le gestionnaire de transactions que nous utilisons est DataSourceTransactionManager, regardons le code source de 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);
    }
}

Regardons @3.1-1 : la méthode doGetTransaction, utilisée pour obtenir l'objet transaction

3.2, doGetTransaction : obtenir l'objet de transaction

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

Examinons @3.2-4le code ci-dessous. C'est le point clé. Il utilise une nouvelle classe TransactionSynchronizationManager:事务同步管理器. Qu'est-ce que la synchronisation ? Dans un processus de transaction, les méthodes appelées sont exécutées en série dans un thread, qui est la synchronisation ; beaucoup de ThreadLocal est utilisé dans cette classe pour stocker des informations liées à la transaction dans le thread, jetons un coup d'œil

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

Regardons le code TransactionSynchronizationManager.getResource

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

getDataSource() renverra l'objet datasource dans le gestionnaire de transactions

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

Regardons le code source de 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;
}

La méthode doGetResource(actualKey) est la suivante. En interne, l'objet ConnectionHolder de données sera obtenu à partir du ThreadLocal des ressources. Jusqu'à présent, aucune donnée n'a été placée dans la ressource. Le conHolder obtenu doit être nul

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 : cela peut être compris comme la recherche de l'objet ConnectionHolder lié par transactionManager.datasource à partir de la ressource ThreadLocal

À ce stade, la méthode Object transaction = doGetTransaction() est exécutée. Revenons à la méthode getTransaction. La première fois que nous entrons, il n'y a pas de transaction dans le contexte, nous allons donc passer au code @3.1-4 suivant . Il n'y a actuellement aucune transaction, ce qui signifie qu'aucune transaction ne doit être suspendue, la méthode de suspension peut donc être ignorée en premier

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

Ensuite, le code suivant sera exécuté

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

Concentrons-nous sur le processus ci-dessus @3.1-7 et @3.1-8

3.3, @3.1-7 : doBegin démarre la 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 sur le code suivant

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

code source

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

Une fois le code ci-dessus exécuté, datasource->ConnectionHoloder(conn) est placé dans la carte des ressources Threadloca.

3.4, @3.1-8 : prepareSynchronization prépare la synchronisation des transactions

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

Le code source est le suivant. Jetez un coup d'œil. La fonction principale de cette méthode est que lorsqu'une nouvelle transaction est démarrée, l'état de la transaction, le niveau d'isolement, s'il s'agit d'une transaction en lecture seule et le nom de la transaction sont jetés dans divers ThreadLocals correspondant dans le TransactionSynchronizationManager. Il est pratique de partager ces données dans le thread actuel.

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 : Initialiser la synchronisation des transactions

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 Résumé

Le processus d'obtention des transactions est terminé, jetons un coup d'œil à certaines choses clés faites dans ce processus

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

4. Ajouter, supprimer, modifier et archiver la méthode de transaction

Prenez l'opération d'insertion suivante pour voir comment cette insertion participe à la transaction de printemps.

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

Au final, il entrera dans la méthode jdbctemplate#execute, nous éliminerons le code inutile, et nous concentrerons sur la méthode interne d'obtention de la connexion ci-dessous

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() renverra l'objet jdbctemplate.datasource. Concentrons-nous sur le code source de DataSourceUtils.getConnection, et enfin entrons dans la méthode suivante

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

Une conclusion peut être tirée : si le sql final exécuté doit être contrôlé par la transaction Spring, alors l'objet de source de données dans le gestionnaire de transactions doit être le même que jdbctemplate.datasource. Cette conclusion a été dite à plusieurs reprises dans d'autres articles, et tout le monde ici est engagé Comprenez.

5. Soumettez la transaction

Appelez la méthode commit du gestionnaire de transactions pour valider la transaction

platformTransactionManager.commit(transactionStatus);

valider le code source

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 le code source

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

La méthode ci-dessus semble assez longue, et elle se concentrera sur trois choses :

1. Points d'extension pour le développement : la méthode commençant par trigger est un point d'extension réservé au développement. Certains rappels peuvent être exécutés pendant l'exécution de la transaction, principalement avant la soumission de la transaction, après la soumission, avant le rollback et le rollback. Après cela, certains rappels peuvent être exécutés. , ce que la synchronisation des transactions doit faire. Ce point d'extension sera abordé ultérieurement.

2. Exécutez l'opération de validation via la connexion , correspondant au code @5-1 ci-dessus : doCommit(status);

3. Effectuez le nettoyage après l'achèvement : exécutez cleanupAfterCompletion(status) dans finally ;

Examinons la méthode doCommit(status) . L'essentiel à l'intérieur est d'appeler le commit() de la connexion pour valider la transaction, comme suit :

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) : opération de nettoyage

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

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

Pour conclure, la principale chose à faire dans le travail de nettoyage est de libérer toutes les ressources occupées par le thread en cours, puis de reprendre la transaction suspendue .

6. Opération de restauration

L'opération de restauration est similaire à l'opération de soumission, donc je ne parlerai pas du code source, jetons un coup d'œil par vous-même.

7. Comment gérer l'existence des affaires?

Regardons un autre processus. Un REQUIRED_NEW est imbriqué dans REQUIRED, puis lorsqu'il atteint REQUIRED_NEW, comment le code s'exécute-t-il ? Le processus général est le suivant

1. Déterminez s'il y a une transaction dans le texte en ligne

2. Suspendre la transaction en cours

3. Ouvrir une nouvelle transaction et exécuter une nouvelle transaction

4. Reprendre les transactions suspendues

7.1. Déterminer s'il existe une transaction : isExistingTransaction

Il est relativement simple de juger s'il y a une transaction dans le texte en ligne, comme suit :

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. S'il y a une transaction en cours

Voyons comment obtenir la transaction, s'il y a une 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);
    }
}

Il y a actuellement une transaction, puis elle entrera dans la méthode 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;
        }
    }
    //其他的传播行为走下面。。。,暂时省略了
}

Ce qui suit se concentre sur les opérations de suspension et de récupération des transactions.

7.3. Suspension de la transaction : suspendre

La suspension de la transaction appelle la méthode suspend du gestionnaire de transaction, le code source est le suivant, la principale chose à faire : enregistrer toutes les informations de la transaction en cours dans l'objet SuspendedResourcesHolder, ce qui équivaut à un instantané de la transaction, qui sera utilisé lors de la restauration ultérieure ; puis nettoyez le site de transaction, principalement pour tuer un tas de données de transaction stockées dans 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);
        }
    }
}

Examinons @1:doSuspend(transaction)le code source. L'essentiel est de dissocier datasource->connectionHolder de la ressource ThreadLocal, puis de renvoyer connectionHolder. La méthode suivante renvoie en fait l'objet 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());
}

À ce stade, la transaction en cours est suspendue, puis une nouvelle transaction est lancée. Le processus de la nouvelle transaction a été présenté ci-dessus. Examinons le processus de récupération de la transaction.

7.4, récupération de transaction : reprendre

La suspension de la transaction appelle la méthode de reprise du gestionnaire de transactions. Le code source est le suivant. La principale chose à faire est de reprendre la transaction suspendue via l'objet SuspendedResourcesHolder. L'objet SuspendedResourcesHolder stocke toutes les informations de la transaction suspendue, vous pouvez donc transmettre cet objet pour reprendre les 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. Interface de rappel lors de l'exécution de la transaction : TransactionSynchronization

8.1. Fonction

Lors de l'exécution des transactions Spring, certains points d'extension sont réservés aux développeurs et certaines méthodes des points d'extension seront rappelées à différentes étapes de l'exécution de la transaction.

Par exemple, si nous voulons effectuer certaines transactions avant la validation de la transaction, après la validation, avant la restauration et après la restauration, nous pouvons le faire via des points d'extension.

8.2. Utilisation des points d'extension

1. Définir l'objet transaction TransactionSynchronization

Les méthodes de l'interface TransactionSynchronization seront automatiquement rappelées lors de l'exécution de la transaction 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. Enregistrez TransactionSynchronization dans la transaction en cours

Enregistrez le point d'extension de transaction TransactionSynchronization dans la transaction actuelle via la méthode statique suivante

TransactionSynchronizationManager.registerSynchronization(transactionSynchronization)

Regardez le code source, c'est très simple, jetez-le dans 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);
}

Lorsqu'il existe plusieurs TransactionSynchronizations, l'ordre peut être spécifié et l'interface org.springframework.core.Ordered peut être implémentée pour spécifier l'ordre. L'ordre est appelé du plus petit au plus grand. TransactionSynchronization a un adaptateur par défaut TransactionSynchronizationAdapter, qui implémente l'interface Ordered, donc, si nous voulons l'utiliser, utilisez directement la classe TransactionSynchronizationAdapter.

3. Rappeler la méthode dans le point d'extension TransactionSynchronization

La méthode dans TransactionSynchronization est automatiquement appelée par le gestionnaire de transactions Spring. Comme mentionné dans cet article, le gestionnaire de transactions appellera la méthode au début du déclencheur à de nombreux endroits pendant le processus de soumission ou d'annulation de transaction. Cette méthode de déclencheur traversera La liste transactionSynchronization dans la transaction actuelle, puis appelle certaines méthodes spécifiées à l'intérieur de transactionSynchronization.

Prenons le code source de la soumission de la transaction comme exemple, jetons un coup d'œil

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

triggerBeforeCommit (statut) code source

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. Voici un cas

1. Exécutez 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. Code de cas

Le code est relativement simple, pas grand chose à expliquer, exécutez la méthode de test 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. Sortie
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}]

Générez le code source du cas correspondant pour que tout le monde puisse le comprendre.

en conclusion

Le contenu d'aujourd'hui est assez long, merci pour votre travail acharné, mais je pense que si vous avez une compréhension approfondie des affaires du printemps, vous y gagnerez beaucoup, allez !

Si vous avez des questions sur les transactions, n'hésitez pas à me laisser un message, le prochain article analysera le code source des transactions déclaratives, alors restez connectés ! ! **

Code source du cas

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

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

Passant A Tous les codes de cas java seront mis dessus à l'avenir, tout le monde le regarde, vous pouvez continuer à faire attention à la dynamique.

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
après :[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=test2-1}, { id=4, nom=test2-2}]


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

### 总结一下

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

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

### 案例源码

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

Le code source correspondant au cas dans cet 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

Je suppose que tu aimes

Origine blog.csdn.net/china_coding/article/details/130779283
conseillé
Classement