understanding of affairs

transaction concept

We need to understand the concept of transactions: What is a transaction? A transaction is a unit of concurrency control and a user-defined sequence of operations. There are four properties (ACID):

  • Atomicity: A transaction is a logical working unit of the database. All operations included in the transaction are either done or not done at all.
  • Consistency: The result of transaction execution must be to change the database from one consistency state to another consistency state. Consistency and atomicity are closely related.
  • Isolation: The execution of a transaction cannot be interfered with by other transactions.
  • Durability: Once a transaction is committed, its changes to the data in the database should be permanent.

The above is a written explanation. To put it simply, it means to unify your operations. Either all operations are successful or none of them are successful. If an operation fails during execution, all previous operations will be rolled back to the point where they were not executed. The state before a series of operations.

Dirty read, non-repeatable read, phantom read

It will be much simpler to understand these three data reading problems caused by concurrent access first, and then understand the transaction isolation level.

dirty read

Transaction A reads uncommitted data from transaction B. If an error occurs in transaction B and a rollback operation is performed, the data read by transaction A is dirty data. It's like the original data was relatively clean and pure, but because transaction B changed it, the data became no longer pure. At this time, transaction A immediately read the dirty data, but transaction B found out and used rollback to restore the data to its original clean and pure state, but transaction A knew nothing about it. The final result was that transaction A read This dirty data is called dirty reading.

This situation often occurs during transfer and withdrawal operations

img

Non-repeatable reading (read multiple times before and after, data content is inconsistent)

Transaction A is performing a read operation. Since the entire transaction A is relatively large, it takes a long time to read the same piece of data before and after. When transaction A reads data for the first time, for example, it reads Xiao Ming's age as 20 years old, transaction B performs a change operation and changes Xiao Ming's age to 30 years old. At this time, transaction A reads Xiao Ming's age for the second time. When the age is reached, it is found that its age is 30 years old, which is different from the previous data, that is, the data is no longer repeated. The system cannot read repeated data and it becomes a non-repeatable read.

img

Phantom reading (multiple reads before and after, the total amount of data is inconsistent)

When transaction A performs a read operation, it needs to count the total amount of data twice. After the previous query of the total amount of data, after transaction B performed the operation of adding new data and submitted it, the total amount of data read by transaction A at this time It was different from the previous statistics. It was like an hallucination. There were a few more data for no reason and it became a phantom reading.

img

Summary: What is the difference between non-repeatable reading and phantom reading?

(1) Non-repeatable reading is to read data changed by other transactions, for update operations

Solution: Use row-level locks to lock the row. Transaction A will release the lock only after completing multiple read operations. Only then will other transactions be allowed to change the data.

(2) Phantom reading is to read data newly added by other transactions, for insert and delete operations

Solution: Use table-level locks to lock the entire table. Transaction A reads the total amount of data multiple times before releasing the lock. Only at this time can other transactions add data.

It will be much simpler to understand the transaction isolation level at this time.

Isolation level of database transactions

The four isolation levels defined by the SQL standard are adopted by ANSI (American National Standards Institute) and ISO/IEC (International Standards). Each level has a different impact on transaction processing capabilities. A transaction is a series of actions, which together form a complete unit of work. All these actions must be completed. If one of them fails, the transaction will be rolled back to the original state, as if nothing happened. .

There are four isolation levels for database transactions, from low to high: Read uncommitted, Read committed, Repeatable read, and Serializable. These four levels can solve the problems of dirty reads, non-repeatable reads, and phantom reads one by one.

img

DEFAULT

The default value indicates that the default isolation level of the underlying database is used. Most databases are READ_COMMITTED (MySql defaults to REPEATABLE_READ)

READ UNCOMMITTED (read uncommitted)

This isolation level means that one transaction can read data that has been modified by another transaction but has not yet been committed. This level does not prevent dirty reads and non-repeatable reads, so this isolation level is rarely used.

READ_COMMITTED (read committed)

This isolation level means that a transaction can only read data that has been submitted by another transaction. This level prevents dirty reads and is the recommended value in most cases.

REPEATABLE_READ (repeatable read)

This isolation level means that a transaction can execute a query multiple times throughout the entire process and return the same records each time. Even if there is new data between multiple queries to satisfy the query, these new records will be ignored. This level prevents dirty reads and non-repeatable reads.

SERIALIZABLE (serialization)

All transactions are executed one after another in order, so that there is no possibility of interference between transactions. In other words, this level can prevent dirty reads, non-repeatable reads and phantom reads. But this will seriously affect the performance of the program. Normally this level is not used. Under this isolation level, transactions are executed serially and sequentially. The InnoDB engine of the MySQL database will implicitly add a read shared lock to the read operation, thereby avoiding the problems of dirty reads, non-repeatable reads, and phantom reads.

MVCC (Multiple Version Concurrency Control)

In mysql, the default transaction isolation level is repeatable read (repeatable-read). In order to solve non-repeatable read, innodb uses MVCC (multi-version concurrency control) to solve this problem. MVCC uses two hidden columns (creation version number and deletion version number) added after each piece of data. Each transaction will have an incrementing version number at the beginning, which is used to compare with the queried version of each row of records. number for comparison. MYSQLMVCC

Spring transaction propagation behavior

First, let’s introduce how to use Spring transaction propagation behavior:

@Transactional(propagation=Propagation.REQUIRED)
public void test() {
    
    
        //todo something
}

The annotation @Transactional is set using the propagation attribute, for example: @Transactional(propagation = Propagation.REQUIRED)

Its propagation attribute values ​​are as follows:

public enum Propagation {
    
    

    REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),

    SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),

    MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),

    REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),

    NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),

    NEVER(TransactionDefinition.PROPAGATION_NEVER),

    NESTED(TransactionDefinition.PROPAGATION_NESTED);

}

Transaction communication behavior:

  • REQUIRED: If a transaction currently exists, join the transaction; if there is no transaction currently, create a new transaction.
  • SUPPORTS: If there is currently a transaction, join the transaction; if there is currently no transaction, continue running in a non-transactional manner.
  • MANDATORY: If there is currently a transaction, join the transaction; if there is no transaction currently, throw an exception.
  • REQUIRES_NEW: Create a new transaction. If a transaction currently exists, suspend the current transaction.
  • NOT_SUPPORTED: Run in non-transactional mode. If a transaction currently exists, the current transaction will be suspended.
  • NEVER:Run in non-transactional mode and throw an exception if a transaction currently exists.
  • NESTED: If a transaction currently exists, create a transaction to run as a nested transaction of the current transaction; if there is no transaction currently, this value is equivalent to REQUIRED

Two implementations of Spring transactions

Spring supports two methods: " 编程式事务" management and " 声明式事务" management:

1 编程式事务: Programmatic transactions use TransactionTemplate or directly use the underlying PlatformTransactionManagertransaction to implement transactions. For programmatic transactions, Spring recommends using TransactionTemplate to manage transactions.

2 声明式事务: Declarative transactions are built on AOP. Its essence is to intercept the method before and after, then create or join a transaction before the target method starts, and "submit" or "rollback" the transaction according to the execution situation after the target method is executed.

The difference between two types of transaction management
  • Programmatic transactions allow users to precisely define transaction boundaries in their code.
  • Declarative transactions help users decouple operations from transaction rules. It is implemented by the Spring container based on AOP, so developers only focus on business logic implementation.
  • Programmatic transactions invade the business code, but provide more granular transaction management. Declarative transactions are based on AOP, so they can play a transaction role without affecting the specific implementation of business code. Generally speaking, it is recommended to use declarative transactions, especially the @Transactional annotation, which can help developers implement transactions while also reducing the amount of code development and making the code look cleaner and cleaner.
Spring programmatic transactions

Generally speaking, there are two ways to implement programmatic transactions: 模板事务的方式(TransactionTemplate)and平台事务管理器方式(PlatformTransactionManager)

  • Template transaction method (TransactionTemplate): Mainly using the TransactionTemplate class to implement transactions, which is also a programmatic usage method officially recommended by Spring;

example:

  • ① Get the template object TransactionTemplate;
  • ② Select the transaction result type;
  • ③ Business data operation and processing;
  • ④ The business execution is completed and the transaction is submitted or an exception occurs and is rolled back;

The execute of TransactionTemplate can accept two types of parameters to execute transactions, namely:

 TransactionCallback<Object>(): 执行事务且可以返回一个值。
 TransactionCallbackWithoutResult(): 执行事务没有返回值。

The following is an example of using TransactionTemplate:

  @Service
public class TransactionExample {
    
    
    /** 1、获取 TransactionTemplate 对象 **/
    @Autowired
    private TransactionTemplate transactionTemplate;

    public void addUser() {
    
    
        // 2、使用 TransactionCallback 或者 TransactionCallbackWithoutResult 执行事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
    
    
            @Override
            public void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
    
    
                try {
    
    
                    // 3、执行业务代码(这里进行模拟,执行多个数据库操作方法)
                    userMapper.delete(1);
                    userMapper.delete(2);
                } catch (Exception e) {
    
    
                    // 4、发生异常,进行回滚
                    transactionStatus.setRollbackOnly();
                }
            }
        });
    }

}

  • Platform transaction manager method (PlatformTransactionManager): Here, the most basic transaction management authority is used to manage transactions, and transactions are operated with the help of Spring transaction's PlatformTransactionManager and the three core classes of TransactionDefinition and TransactionStatus.

Use transaction manager to implement transaction steps:

  • ① Get the transaction manager PlatformTransactionManager;
  • ② Get the transaction attribute definition object TransactionDefinition;
  • ③ Get the transaction status object TransactionStatus;
  • ④ Business data operation and processing;
  • ⑤ Perform transaction commit operation or perform transaction rollback operation when an exception occurs;
@Service
public class TransactionExample {
    
    

    /** 1、获取 PlatformTransactionManager 对象 **/
    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    public void addUser() {
    
    
        // 2、获取默认事务定义
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        // 设置事务传播行为
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        // 3、根据事务定义对象设置的属性,获取事务状态
        TransactionStatus status = platformTransactionManager.getTransaction(def);
        try {
    
    
            // 4、执行业务代码(这里进行模拟,执行多个数据库操作方法)
            userMapper.delete(1);
            userMapper.delete(2);
            // 5、事务进行提交
            platformTransactionManager.commit(status);
        } catch(Exception e){
    
    
            // 5、事务进行回滚
            platformTransactionManager.rollback(status);
        }
    }

}
Spring declarative transactions

Declarative transaction management (declarative transaction management), as the name implies, uses a declarative approach to handle transactions. This method is implemented based on Spring AOP and decouples specific business logic and transaction processing. Its essence is to intercept before and after executing the method, create or join a transaction before the method starts, and submit or submit according to the execution situation after the target method is executed. Roll back the transaction.

Commonly used declarative transaction methods

Commonly used declarative transaction methods include

  • 1 XML
  • 2 @Transactional annotation

Of the two methods, due to the popularity of SpringBoot in recent years, which provides very convenient automated configuration, the XML method has been gradually phased out, and the annotation method is more recommended.

Scope of @Transactional

The annotation @Transactional can be added not only to methods, but also to the class level. When the annotation is placed at the class level, it means that all public methods of the class are configured with the same transaction attribute information. If @transactional is configured at the class level and @transactional is also configured at the method level, the application will use the method-level transaction attribute information to manage transactions. In other words, the method-level transaction attribute information will override the relevant configuration at the class level.

Configurable parameters in @Transactional annotation

  • value: Transaction manager, this configuration item is to set the Bean name in the Spring container. This Bean needs to implement the interface PlatformTransactionManager.

  • transactionManager: Transaction manager, this parameter is consistent with the value configuration and is the same thing.

  • isolation: transaction isolation level,默认为 Isolation.DEFAULT 级别

  • propagation: Transaction communication behavior,默认为 Propagation.REQUIRED

  • timeout: Transaction timeout, unit is seconds, default value is -1, when transaction times out, an exception will be thrown and rollback operation will be performed.

  • readOnly: Whether to enable read-only transactions, whether to enable read-only transactions,默认 false

  • rollbackForClassName: The exception class name definition of the rollback transaction is the same as rollbackFor, but it is defined with the class name.

  • noRollbackForClassName: Specify which exception names do not roll back the transaction. The parameter is a class array. It is the same as noRollbackFor, but it is defined using the name of the class.

  • rollbackFor: Rollback transaction exception class definition. When an exception occurs in the method and the exception class is the same as the class specified by this parameter, the rollback operation is performed, otherwise the transaction is committed.

  • noRollbackFor
    

    : Specify which exceptions occur and do not roll back the transaction. When an exception occurs in the method and the exception class is the same as the class specified by this parameter, the transaction will not be rolled back but will continue to be submitted. Example

    @Transactional(propagation=Propagation.REQUIRED)
    public void test() {
          
          
          //todo something
    }
    

    Note: Generally speaking, it is not recommended to configure @Transaction on a class, because it is likely that subsequent maintainers will have to force the use of transactions.

Points to note when using transactions

  • 1. No rollback when encountering exception detection. Reason: Rollback is only performed at the default RuntimeException level. If it is an Eexception level exception, it needs to be added manually.

    @Transactional(rollbackFor=Exception.class)
    
  • 2. Things do not take effect after catching the exception. The reason is: catching and processing the exception causes the framework to be unable to perceive the exception, and naturally it cannot be rolled back. Suggestion: If it is not an actual business requirement, throw exceptions uniformly at the business layer and then handle them uniformly at the control layer.

    @Transactional(rollbackFor=Exception.class)
    public void test() {
          
          
       try {
          
          
            //业务代码
       } catch (Exception e) {
          
          
           // TODO: handle exception
       }
       //主动捕捉异常导致框架无法捕获,从而导致事物失效
    }
    
  • 3. In Spring, if a business method is completely wrapped by try catch, then this business method is equivalent to being separated from Spring transaction management, because no exception will be thrown from the business method! All are captured and swallowed, causing the Spring exception to be thrown and trigger the transaction rollback strategy to fail. However, it is not a bad idea if you use the Spring api to explicitly roll back the transaction by hard-coding the page in the catch code block. Perform manual exception rollback directly

  @Transactional(rollbackFor=Exception.class)
  public void test() {
    
    
     try {
    
    
          //业务代码
     } catch (Exception e) {
    
    
     	 //手动回滚事务,发生嵌套式事务时,return不好使,所以手动回滚事务,也可以向上抛异常回滚
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
         // TODO: handle exception
     }
     //主动捕捉异常导致框架无法捕获,从而导致事物失效
  }

Rollback partial exception

  @Override
@Transactional(rollbackFor = Exception.class)
public Object submitOrder (){
    
      
    success();  
    //只回滚以下异常,
    Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
    try {
    
      
        exception(); 
     } catch (Exception e) {
    
      
        e.printStackTrace();     
        //手工回滚异常
        TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savePoint);
        return ApiReturnUtil.error();
     }  
    return ApiReturnUtil.success();
}

Reprinted at: https://zhuanlan.zhihu.com/p/337921874

Guess you like

Origin blog.csdn.net/ITKidKid/article/details/127637098