springBoot service Layer Transaction Control Operations

  • 2021-08-21 20:43:05
  • OfStack

springBoot is simple to use, add @ EnableTransactionManagement annotation on Application startup class s, and then add @ Transactional annotation on service layer method

@ Transactional properties

属性 类型 描述
value String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean 读写或只读事务,默认读写
timeout int (in seconds granularity) 事务超时时间设置
rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

Usage:

@ Transactional can act on interfaces, interface methods, classes, and class methods. When used on a class, all public methods of the class will have transactional attributes of that type, and we can also use this annotation at the method level to override the definition at the class level.

Although the @ Transactional annotation can be used on interfaces, interface methods, classes, and class methods, Spring does not recommend using the annotation on interfaces or interface methods because it only takes effect when using interface-based proxies.

In addition, the @ Transactional annotation should only be applied to the public method, which is determined by the nature of Spring AOP.

If you use the @ Transactional annotation on protected, private, or default visibility methods, this will be ignored and no exception will be thrown.

By default, only method calls from outside are captured by the AOP proxy, that is, calls by methods inside the class to other methods inside the class do not cause transactional behavior, even if the called method is decorated with the @ Transactional annotation.

Annotation on method:


@Autowired 
private MyBatisDao dao; 
@Transactional 
@Override 
public void insert(Test test) { 
 dao.insert(test); 
 throw new RuntimeException("test");// Throw unchecked Exception, trigger thing, rollback  
} 

 @Transactional(noRollbackFor=RuntimeException.class) 
 @Override 
 public void insert(Test test) { 
  dao.insert(test); 
  // Throw unchecked Exception, triggering things, noRollbackFor=RuntimeException.class, No rollback  
  throw new RuntimeException("test"); 
 } 

@Transactional(propagation=Propagation.NOT_SUPPORTED) 
@Override 
public void insert(Test test) { 
 // The behavior of spreading things is PROPAGATION_NOT_SUPPORTED Is run in a non-transactional manner and is not stored in the database  
 dao.insert(test); 
} 

Annotation on class: When used on a class, all public methods of the class will have transactional attributes of this type


@Transactional 
public class MyBatisServiceImpl implements MyBatisService { 
 @Autowired 
 private MyBatisDao dao; 
   
 @Override 
 public void insert(Test test) { 
  dao.insert(test); 
  // Throw unchecked Exception, trigger thing, rollback  
  throw new RuntimeException("test"); 
 } 

Note: Sometimes, during development, annotations are added but cannot be rolled back

Reason: The default spring transaction is rolled back only when an uncaptured RuntimeException occurs.

spring aop Exception Capture Principle: Intercepted methods need to explicitly throw exceptions, and can not be handled by any means, so that aop proxy can catch method exceptions and roll back. By default, aop only catches RuntimeException exceptions, but specific exceptions can be caught and rolled back through configuration

In other words, try catch is not used in the method of service or throw new runtimeexcetpion () is added at the end of catch, so that if the program is abnormal, it can be caught by aop and rolled back.

Solution:

1. Throw an RuntimeException exception in the service layer method (if you need to throw a custom exception in Catch, you only need to inherit the custom exception from RuntimeException), and continue to catch and handle this exception.

2. In the catch statement of the service layer method, add:


TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

Statement, manually rollback, so that the upper layer does not need to handle exceptions.

Supplement: springboot Transactions that multiple service call each other

Today, I want to call the method B of another service in the method A of one service. Both the method A and the method B have database insertion operation, and the @ Transaction annotation is also added. However, when an exception is thrown in the B method, the insertion statement in A can still be executed successfully.

The annotation configuration is as follows:


@Transactional(isolation= Isolation.DEFAULT,propagation= Propagation.REQUIRED ) 

I can't understand it. After searching for relevant information, the problem still lies in the configuration of @ Transaction annotation, and it is necessary to configure exception rollback.


@Transactional(isolation= Isolation.DEFAULT,propagation= Propagation.REQUIRED,rollbackFor = Exception.class)

Thus, when an exception is thrown in the B method, the operation in the A is rolled back and the transaction takes control.


Related articles: