SoFunction
Updated on 2025-03-06

Interpret how Spring transactions are implemented

How to implement Spring transactions

The transaction base is based on database transactions and AOP mechanisms.

2. First, for beans that use @Transactional annotation, Spring will create a proxy object as the bean

3. When calling the method of the proxy object, we will first determine whether the @Transactional annotation is added to the method.

4. If added, then use the transaction manager to create a database connection.

5. And modify the autocommit attribute of the database connection to false, and prohibit the automatic commit of this connection. This is a very important step in implementing Spring transactions.

6. Then execute the current method, and SQL will be executed in the method

7. After executing the current method, if no exception occurs, the transaction will be submitted directly.

8. If an exception occurs and this exception needs to be rolled back, the transaction will be rolled back, otherwise the transaction will still be submitted.

Note:

The isolation level of a transaction corresponds to the isolation level of a database

The transaction propagation mechanism is implemented by Spring transactions itself, and is also the most complex in Spring transactions.

The transaction propagation mechanism is based on a database connection. A database connection is a transaction. If the propagation mechanism is configured to require a new transaction, then it is actually to create a new database connection first and execute SQL on this new database connection.

Several ways to implement Spring transactions

Several ways to implement transactions

(1) Programming transaction management is the only choice for POJO-based applications. We need to call beginTransaction(), commit(), rollback() and other transaction management related methods in the code, which is programming transaction management.

(2) Declarative transaction management based on TransactionProxyFactoryBean

(3) Declarative transaction management based on @Transactional

(4) Configure transactions based on Aspectj AOP

Programmatic transaction management

1、transactionTemplate

This method is automatic transaction management without manually opening, committing, or rolling back.

Configure Transaction Manager

<!-- Configure Transaction Manager ,Encapsulate all transaction operations,Rely on connection pool -->
       <bean  class="">
               <property name="dataSource" ref="dataSource"></property>
       </bean>

Configure transaction template objects

<!-- Configure transaction template objects -->
       <bean  class="">
            <property name="transactionManager" ref="transactionManager"></property>
        </bean>

test

@Controller
@RequestMapping("/tx")
@RunWith()
@ContextConfiguration(locations = {"classpath:"})
public class TransactionController {

    @Resource
    public TransactionTemplate transactionTemplate;

    @Resource
    public DataSource dataSource;

    private static JdbcTemplate jdbcTemplate;

    private static final String INSERT_SQL = "insert into cc(id) values(?)";
    private static final String COUNT_SQL = "select count(*) from cc";

    @Test
    public void TransactionTemplateTest(){
        //Get jdbc core class object and then operate the database        jdbcTemplate = new JdbcTemplate(dataSource);
        //Get the transaction template object configured in xml through annotation        (TransactionDefinition.ISOLATION_READ_COMMITTED);
        //Rewrite the execute method to achieve transaction management        (new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                (INSERT_SQL, "33");   //The field sd is int type, so the insertion will definitely fail and the exception will be reported, and it will automatically roll back, which means that TransactionTemplate will automatically manage transactions            }
        });
        int i = (COUNT_SQL);
        ("Total number of records in the table:"+i);
    }

}

2、PlatformTransactionManager

Use the Transaction Manager PlatformTransactionManager object, PlatformTransactionManager is an interface class implemented by DataSourceTransactionManager

In this way, transactions can be manually opened, submitted, and rolled back.

Just need: Configure transaction management

<!-- Configure transaction management ,Encapsulate all transaction operations,Rely on connection pool -->
       <bean  class="">
               <property name="dataSource" ref="dataSource"></property>
       </bean>

test

@Controller
@RequestMapping("/tx")
@RunWith()
@ContextConfiguration(locations = {"classpath:"})
public class TransactionController {

   @Resource
    public PlatformTransactionManager transactionManager;//This is to inject the configuration data management object into it.    
    @Resource
    public DataSource dataSource;
    
    private static JdbcTemplate jdbcTemplate;

    private static final String INSERT_SQL = "insert into cc(id) values(?)";
    private static final String COUNT_SQL = "select count(*) from cc";

    @Test
    public void showTransaction(){
        //Define the use of isolation level and propagate behavior        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        (TransactionDefinition.ISOLATION_READ_COMMITTED);
        (TransactionDefinition.PROPAGATION_REQUIRED);
        // Transaction state class, obtained according to the transaction definition through the getTransaction method of PlatformTransactionManager; after obtaining the transaction state, Spring decides how to start the transaction based on the propagation behavior.        TransactionStatus transaction = (def);
        jdbcTemplate = new JdbcTemplate(dataSource);
        int i = (COUNT_SQL);
        ("Total number of records in the table:"+i);
        try {
            (INSERT_SQL,"2");
            (INSERT_SQL,"whether");//Exception occurs because the field is of type int, an exception will be reported and will be automatically rolled back            (transaction);
        }catch (Exception e){
            ();
            (transaction);
        }
        int i1 = (COUNT_SQL);
        ("Total number of records in the table:"+i1);
    }
}

Declarative transaction management

1. Start transactions based on Aspectj AOP

Configure transaction notifications

<!--        Configure transaction enhancement -->
       <tx:advice   transaction-manager="transactionManager">
          <tx:attributes>
              <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" />
          </tx:attributes>
       </tx:advice>

Configuration weaving

<!--       aopAgent Affairs。scanning  All methods under the path -->
       <aop:config>
       <!--     scanning  All methods under the path,And join transactions -->
          <aop:pointcut   expression="execution(* .*.*(..))" />
          <aop:advisor advice-ref="txAdvice" pointcut-ref="tx" />
      </aop:config>

A complete example

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/schema/beans"
       xmlns:xsi="http:///2001/XMLSchema-instance"
       xmlns:aop="/schema/aop"
       xmlns:context="/schema/context"
       xmlns:tx="/schema/tx"
       xsi:schemaLocation="/schema/beans
           /schema/beans/spring-beans-3.
           /schema/aop
           /schema/aop/spring-aop-3.
           /schema/context
           /schema/context/spring-context-3.
           /schema/tx
           /schema/tx/spring-tx-3.">
           
       <!-- Create a load externalPropertiesFile Object -->
       <bean class="">
               <property name="location" value="classpath:"></property>
       </bean>
    <!-- IntroducedredisProperties Configuration File -->
    <import resource="classpath:"/>

       <!-- Configure database connection resources -->
       <bean  class="" scope="singleton">
               <property name="driverClassName" value="${driver}"></property>
               <property name="url" value="${url}"></property>
               <property name="username" value="${username}"></property>
               <property name="password" value="${password}"></property>

               <property name="maxActive" value="${maxActive}"></property>
               <property name="maxIdle" value="${maxIdle}"></property>
               <property name="minIdle" value="${minIdle}"></property>
               <property name="initialSize" value="${initialSize}"></property>
               <property name="maxWait" value="${maxWait}"></property>
               <property name="removeAbandonedTimeout" value="${removeAbandonedTimeout}"></property>
               <property name="removeAbandoned" value="${removeAbandoned}"></property>

               <!-- ConfigurationsqlHeartbeat pack -->
               <property name= "testWhileIdle" value="true"/>
            <property name= "testOnBorrow" value="false"/>
            <property name= "testOnReturn" value="false"/>
            <property name= "validationQuery" value="select 1"/>
            <property name= "timeBetweenEvictionRunsMillis" value="60000"/>
            <property name= "numTestsPerEvictionRun" value="${maxActive}"/>
       </bean>

<!--createSQLSessionFactoryObject  -->
       <bean  class="">
               <property name="dataSource" ref="dataSource"></property>
               <property name="configLocation" value="classpath:MyBatis_config.xml"></property>
       </bean>

       <!-- createMapperScannerConfigurerObject -->
       <bean class="">
               <property name="basePackage" value=""></property>
       </bean>

       <!-- Configuration扫描器   IOC annotation -->
       <context:component-scan base-package="" />

       <!-- Configuration事务管理 ,Encapsulate all transaction operations,Rely on connection pool -->
       <bean  class="">
               <property name="dataSource" ref="dataSource"></property>
       </bean>

        <!-- Configuration事务模板Object -->
       <bean  class="">
            <property name="transactionManager" ref="transactionManager"></property>
        </bean>

<!--       Configuration事务增强 -->
       <tx:advice   transaction-manager="transactionManager">
          <tx:attributes>
              <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" />
          </tx:attributes>
       </tx:advice>
       
<!--     aopAgent Affairs -->
       <aop:config>
          <aop:pointcut   expression="execution(* .*.*(..))" />
          <aop:advisor advice-ref="txAdvice" pointcut-ref="tx" />
      </aop:config>
</beans>

This way, even if all the methods are added to the transaction

You can also use the springboot configuration class method:

package ;

@Configurationpublic 
class TxAnoConfig {    
    /*Transaction Intercept Type*/    
    @Bean("txSource")
    public TransactionAttributeSource transactionAttributeSource() {   
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource(); 
        /*Read-only transaction, no update operation*/        
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED, (new RollbackRuleAttribute()));   
        (60);   
        Map<String, TransactionAttribute> txMap = new HashMap<>();   
        ("*", requiredTx);  
        (txMap);    
        return source; 
    }   
    /**   * Face interception rules Parameters will be automatically injected from the container   */    
    @Bean 
    public AspectJExpressionPointcutAdvisor pointcutAdvisor(TransactionInterceptor txInterceptor) { 
        AspectJExpressionPointcutAdvisor pointcutAdvisor = new AspectJExpressionPointcutAdvisor();  
        (txInterceptor);    
        ("execution (* ..*Controller.*(..))");   
        return pointcutAdvisor;   
    } 
    /*Transaction Interceptor*/ 
    @Bean("txInterceptor")   
    TransactionInterceptor getTransactionInterceptor(PlatformTransactionManager tx) {    
        return new TransactionInterceptor(tx, transactionAttributeSource()); 
    }
}

2. Declarative transaction management based on annotation by @Transactional

@Transactional
public int saveRwHist(List list) {
return (list);
}

To enable this annotation, you need to add a configuration to enable annotation transaction.

The above transaction opening method only requires understanding. Nowadays, these methods are generally not used in work, which is too cumbersome. Generally, you can complete these transaction management operations by directly using the @Transactional annotation provided by springboot. However, if you want to know the underlying implementation principle of the transaction, you can still refer to the above primitive methods.

Summarize

These are just personal experience. I hope you can give me a reference and I hope you can support me more.