Explain in detail the operation of @ Transactional things and the troubleshooting of invalid things in SpringBoot

  • 2021-10-13 07:44:37
  • OfStack

Directory 1. spring Transaction Management Brief 2. Use @ Transactional Annotation in SpringBoot 2.1. Open Transaction Annotation 2.2. Add Annotation on Target Class, Method @ Transactional 2.3. Refine Transaction Configuration 3. @ Transactional Transaction Implementation Mechanism 3.1. Overall Transaction Control Flow 3.2. Two Agents for Spring AOP 3.3. Underlying Implementation of Transaction Operations 4. @ Transactional Use Annotation Implementation and Troubleshooting 4.1. Does the Database Engine Support Transactions? 4.3. Is the annotation class loaded as Bean? 4.2. Is the annotation method modified by public? 4.5. Is there a self-calling problem? 4.6. Is the data source used loaded with a transaction manager? 4.4. Is the exception triggering the rollback configured correctly? 4.5. Is the extended configuration of @ Transactional propagation correct? 4.7. Is the optional configuration of transaction management correct?

1. spring transaction management brief

Two transaction management methods:

Coded transaction management: Writing transaction control code in business code. Declarative transaction management: Based on AOP (aspect-oriented programming), transaction management is decoupled from business logic. Two implementations of declarative transaction management: Configured in the configuration file (xml). Based on @ Transactional annotations.

2. Using @ Transactional annotation in SpringBoot

2.1. Turn on transaction annotations

Add the annotation @ EnableTransactionManagement to the main project class, for example:


@EnableTransactionManagement
public class MySpringBootService extends WebMvcConfigurerAdapter {
    public static void main(String[] args) {
        SpringApplication.run(CoreService.class, args);
    }
}

2.2. Add annotations on target classes, methods @ Transactional

1. If @ Transactional is added to a class, it means that all methods of the class turn on transaction management. Such as:


   @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
   @Service
   public class MyServiceImpl implements MyService {
     //class body
   }

2. Adding @ Transactional to a method means that the method opens transaction management. Such as:


       @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
       @Override
       public ActivityPo getActivityById(Long id){
         //method body
       }

3. If @ Transactional exists on a method and @ Transactional also exists on the class to which it belongs, the transaction configuration at the method level prevails.

2.3. Refine transaction configuration

There are many configurable parameters about @ Transactional, mainly propagation, rollbackFor, etc., which can be applied to different scenarios, so we will not elaborate here.

3. @ Transactional transaction implementation mechanism

3.1. Overall transaction control flow

When the @ Transactional annotated method is called by code outside the class, Spring generates an AOP proxy object for the class in which the method belongs at runtime. Based on the @ Transactional property, the proxy object determines whether the transaction interceptor TransactionInterceptor intercepts this method. During transaction interception, the transaction will be started first, and then the business code will be executed. rollback or commit will be carried out through abstract transaction manager AbstractPlatformTransactionManager according to whether there is an exception in execution.

3.2. Spring Two Proxies for AOP

Spring AOP has two kinds of CglibAopProxy and JdkDynamicAopProxy, of which: In the intercept () method of its inner class DynamicAdvisedInterceptor, CglibAopProxy determines whether to intercept transactions. JdkDynamicAopProxy, in its invoke () method, determines whether to intercept transactions.

3.3. Underlying implementation of transactional operations

Both rollback and commit of the abstract transaction manager AbstractPlatformTransactionManager require concrete implementation classes. The parent interface of the abstract transaction manager AbstractPlatformTransactionManager is PlatformTransactionManager. There are many transaction manager implementation classes, such as DataSourceTransactionManager and so on. Different transaction managers manage different data resources DataSource, such as DataSourceTransactionManager managers JDBC data sources. Make sure that the data sources used in the called method are loaded with transaction managers.

4. @ Transactional using annotation implementation and problem troubleshooting

4.1. Does the Database Engine support transactions?

The engine of MySql, MyIsam, does not support transactions. For transaction control to take effect, the engine of libraries and tables must be InnoDB.

4.3. Is the annotation class loaded as Bean?

Article 1 of Section 3.1 mentions that proxy objects need to be generated for classes at run time. The premise is that this class 1 must be managed by Spring and loaded as an Bean object. Make sure your class is annotated by @ Component, @ Service, @ Controller, and so on.

4.2. Is the annotation method modified by public?

In Section 3.2, two AOP agents are mentioned to determine whether to intercept transactions in the intercept () and invoke () methods, respectively. Both methods indirectly call the computeTransactionAttribute method of the AbstractFallbackTransactionAttributeSource class to get the related properties of transaction control. There is the following code:

	/**
	 * Same signature as {@link #getTransactionAttribute}, but doesn't cache the result.
	 * {@link #getTransactionAttribute} is effectively a caching decorator for this method.
	 * <p>As of 4.1.8, this method can be overridden.
	 * @since 4.1.8
	 * @see #getTransactionAttribute
	 */
	protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}
    
    //...
  }
This code causes no-public methods to fail to enter transaction control. Therefore, 1 must ensure that the method that it needs to control transactions contains public modifiers.

4.5. Is there a self-calling problem?

Article 1 of Section 3.1 emphasizes that transaction methods are managed by proxy objects generated by Spring only when they are called by code other than the current class. This logic creates a self-calling problem: @ Transactional does not work when a transaction method is called by an internal method of this class. Self-calling sample code:

@Service
public class PersonServiceImpl implements PersonService{
  @Resource
  private PersonDao personDao;
  
  public void insertPerson(Person person){
    // Self-invocation 
    personService.insert(person);
    
    // Other codes 
    personDao.insertLog...
	}
  
  @Transactional(rollbackFor = Exception.class)
  public void insert(Person person){
    personDao.insert(person);
	}
}
In the above code, if the business logic starts with the non-transactional method insertPerson (), where the transactional method insert () is called, the transaction control is invalid when insert () is excepted. Simply put, in the same class, if the non-transactional method A calls the transactional method B, when the transactional method B is abnormal and the transaction control is invalid, neither A nor B will be rolled back. So, in the same class, if the transactional method A calls the non-transactional method B, and then the non-transactional method B calls the transactional method C, does the transaction take effect? Answer: Yes. Because the transaction method A has already started transaction management when it is called by external code.

4.6. Is the data source used loaded with a transaction manager?

Section 3.3, Section 5, mentions that you should ensure that the data sources used in the called method are loaded with transaction managers. In the SpringBoot project, if it is a single data source, the transaction manager DataSourceTransactionManager is configured for the single data source by default. In the SpringBoot project, if there are multiple data sources, make sure that all data sources are configured with transaction managers. For the configuration method of multiple data sources, please refer to: https://blog. csdn. net/hanchao5272/article/details/81209552 The manual configuration method of transaction manager can be referred to as follows:

@Bean
@Primary
public PlatformTransactionManager primaryTransactionManager(@Qualifier("sqlDataSource") DataSource sqlDataSource) {
  return new DataSourceTransactionManager(sqlDataSource);
}

4.4. Is the exception triggering the rollback configured correctly?

By default, transactional regression is for uncheck exceptions (runtime exceptions) or ERROR. By default, an exception to check does not trigger a rollback, such as FileNotFoundException. If you want to simply configure to roll back for all exceptions, you can do this:

@Transactional(rollbackFor = Exception.class)

4.5. Is the extended configuration of @ Transactional propagation correct?

1 In general, the propagation property does not need to be configured. It uses the default configuration, namely: Propagation. REQUIRED. There are some propagation properties that cause transactions not to trigger. 1 Be sure to note: SUPPORTS: If there is a transaction, enter the transaction; Otherwise, it runs in a non-transactional manner. NOT_SUPPORTED: If a transaction exists, the transaction is suspended and run in a non-transactional manner. NEVER: Run as a non-transaction, throwing an exception if a transaction exists.

4.7. Is the optional configuration of transaction management correct?

In SpringBoot, there are two optional configurations for the configuration of transactions (1 generally does not require configuration):

The @ EnableTransactionManagement of the Springboot startup class. rollback-on-commit-failure properties of Springboot configuration file:

# yaml Configure 
spring:
  transaction:
    rollback-on-commit-failure: true
    
# properties Configure 
spring.transaction.rollback-on-commit-failure=true

Make sure that all the above configurations are correct (or not configured).


Related articles: