Basic use of SpringAop-advanced version

The code address
SpringAop
thinks that the blogger can also give a Star

Earlier we conducted an introduction to the basic version, mainly five notices.
Next we apply to the actual scenario (transaction management):
pom.xml

<dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.14</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

MsgMapper.java

package com.mapper;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface MsgMapper {
    
    

    @Select("INSERT INTO msg VALUES(NULL,'long',1);")
    void insert();
}

MsgService.java

package com.service;

import com.mapper.MsgMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class MsgService {
    
    

    @Autowired
    MsgMapper mapper;

    public void insert(){
    
    
        System.out.println("方法执行中");
        mapper.insert();
    }
}

MsgController.java

package com.web;

import com.service.MsgService;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MsgController {
    
    

    @Autowired
    MsgService msgService;

    @RequestMapping(value = "/test",method = RequestMethod.GET)
    public String test( int j){
    
    
        msgService.insert();
        return "success";
    }
}

Application.java

package com;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(Application.class);
    }
}

We use the most basic ssm framework to simulate transaction management scenarios.
We all know one called transaction rollback.
Transaction rollback: A transaction is a group of operations combined into a logical unit of work. Although errors may occur in the system, the transaction will control and maintain the consistency and integrity of each operation in the transaction. Once a certain logic in the transaction goes wrong, we will undo everything we did before.
ssm can be said to be a good representative. In our process of database operation, if the first step is to store data, and the second step will process the data of the first step, and then hand it to the third step for database Storage, and the first step and the third step must have a corresponding relationship. In this case, we must ensure that the processing of the second step cannot go wrong. Once an error occurs, there will be no third step and no corresponding relationship. So we have to pack these three steps into one transaction. Once a step goes wrong, we can roll it back to avoid the problem of no correspondence.
Well, having said so much, let's explain with code.
Run the above code first.
The operation is successful, visit http://127.0.0.1:8080/test?j=1
database data to add a new
Insert picture description here
entry Okay, this is a normal phenomenon, then I add an operation that will report an error in the method in MsgService.
![Insert picture description here](https://img-blog.csdnimg.cn/20210224200739952.png

Looking at it this way, we know that an error will be reported during the calculation, but the data will still be inserted into the database
to rerun, and visit http://127.0.0.1:8080/test?j=1
Insert picture description here
we find that the data is still inserted, but This data is not inserted in the theoretical logic, at this time we need to use transaction rollback.

  1. @Transactional
    modify MsgService.java
package com.service;

import com.mapper.MsgMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MsgService {
    
    

    @Autowired
    MsgMapper mapper;

    @Transactional
    public void insert(int j){
    
    
        System.out.println("方法执行中");
        mapper.insert();
        int i = j / 0;
    }
}

We directly add the annotations, re-run, and visit http://127.0.0.1:8080/test?j=1
Insert picture description here
There is no additional data in the database. Obviously, we have achieved the effect of transaction rollback.

  1. DataSourceTransactionManager
    DataSourceTransactionManager requires handwriting. Let’s write this transaction by hand.
    Create TransactionUtil.java
package com.util;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

@Component
public class TransactionUtil {
    
    

    /**
     * 获取当前事务管理器
     */
    @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;

    public TransactionStatus begin(){
    
    
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transaction;
    }

    /**
     * 提交事务
     * @param transactionStatus
     */
    public void commit(TransactionStatus transactionStatus){
    
    
        dataSourceTransactionManager.commit(transactionStatus);
    }

    /**
     * 回滚事务
     */
    public void rollback(TransactionStatus transactionStatus){
    
    
        dataSourceTransactionManager.rollback(transactionStatus);
    }
}

The code of MsgService.java is modified again

package com.service;

import com.mapper.MsgMapper;
import com.util.TransactionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;

@Service
public class MsgService {
    
    

    @Autowired
    MsgMapper mapper;
    
    @Autowired
    TransactionUtil transactionUtil;
    
    public void insert(int j){
    
    
        TransactionStatus transactionStatus = transactionUtil.begin();
        try{
    
    
            System.out.println("方法执行中");
            mapper.insert();
            int i = j / 0;
            transactionUtil.commit(transactionStatus);
        }catch (Exception e){
    
    
            transactionUtil.rollback(transactionStatus);
        }
    }
}

The same can be achieved. But here comes the problem. Both of us above are aimed at one method. If there are too many methods, it is impossible for us to add annotations or write by hand every time. It is not realistic. Let's go back to the basic version and reduce redundant code. . Yes, we can also use aop to complete transaction rollback
3. AOP to achieve transaction rollback
Create TransactionAop.java

package com.aop;

import com.util.TransactionUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;

@Aspect
@Component
@EnableAspectJAutoProxy
public class TransactionAop{
    
    

    @Autowired
    TransactionUtil transactionUtil;

    @Pointcut("execution(* com.service..*.*(..))")
    public void transactionAop(){
    
    

    }

    @Around("transactionAop()")
    public void doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        TransactionStatus transactionStatus = transactionUtil.begin();
        try{
    
    
            joinPoint.proceed();
            transactionUtil.commit(transactionStatus);
        }catch (Exception e){
    
    
            transactionUtil.rollback(transactionStatus);
        }
    }
}

This is achieved, for all methods, but. We know that the creation of a bean is a singleton by default. If multiple methods use a singleton, then it will be blocked, then the efficiency will become very slow. So we need to turn TransactionAop into multiple cases and add the annotation @Scope("prototype"). But there are still questions, why not add TransactionUtil to TransactionUtil, and turn TransactionUtil into multiple cases? Because TransactionUtil has multiple instances in a singleton in TransactionAop, then this multiple instances will fail, and it is essentially a singleton.

There is also an interface problem. We will now find that the existence of abnormal calculations has caused our interface to be 500. The processing method is to change the doAround method of TransactionAop. as follows

@Around("transactionAop()")
    public Integer doAround(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        TransactionStatus transactionStatus = transactionUtil.begin();
        try{
    
    
            joinPoint.proceed();
            transactionUtil.commit(transactionStatus);
            return 1;
        }catch (Exception e){
    
    
            transactionUtil.rollback(transactionStatus);
            return 0;
        }
    }

In another case, we don’t want to hand it over to AOP. We can manually roll back the transaction and
modify the insert method in MsgService.java.

public void insert(int j){
    
    
        try{
    
    
            System.out.println("方法执行中");
            mapper.insert();
            int i = j / 0;
        }catch (Exception e){
    
    
            // 手动回滚
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
    }

It should be noted here that if an exception is caught in this method, then the exception cannot be caught in TransactionAop, so the rollback in TransactionAop is not executed.

Guess you like

Origin blog.csdn.net/weixin_43911969/article/details/114037810