Detailed explanation of failure reasons of nested transactions in Springboot

  • 2021-12-12 04:27:53
  • OfStack

First, there are two transaction methods, one of which calls the other.


@Transactional(rollbackFor = Exception.class)
public void trance() {
    try {
        trance1();// Call under 1 Transaction methods. 
    } catch (Exception e) {
        e.printStackTrace();
    }
        User user = new User();
        ShardingIDConfig shardingIDConfig = new ShardingIDConfig();
        user.setId(shardingIDConfig.generateKey().longValue());
        user.setName("trance");
        user.setSex(0);
        userMapper.create(user);
}
 
@Transactional(propagation = Propagation.REQUIRED)
public void trance1() throws Exception{
    User user = new User();
    ShardingIDConfig shardingIDConfig = new ShardingIDConfig();
    user.setId(shardingIDConfig.generateKey().longValue());
    user.setName("trance1");
    user.setSex(1);
    userMapper.create(user);
    System.out.println(user.getId());
    throw new RuntimeException();
}

Add dependencies


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

Then write a test class, which is the first time I have used this test


import com.lijia.App;
import com.lijia.service.UserService;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
 
@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class Test {
    @Autowired
    private UserService userService;
 
    @org.junit.Test
    public void trance(){
        userService.trance();
    }
}

Execution will find that RuntimeException is reported, but there are two pieces of data in the database, indicating that the transaction is invalid

runtimeException

Both pieces of data in the database have been uploaded, indicating that the transaction is invalid

Why is this happening
spring transactions use dynamic proxies. Or look at it from the dynamic agent.
Give 1 piece of code


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; 
interface IHello {
    public void test(); 
    public void test1();
} 
class Hello implements IHello{
    @Override
    public void test() {
        System.out.println("test");
    }
 
    @Override
    public void test1() {
        System.out.println("test1");
    }
}
public class MyInvoke implements InvocationHandler{
    public Object target;
 
    public MyInvoke(Object target){
        this.target = target;
 
    }
     @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().contains("test")){
            System.out.println("======== Acting =======");
        }
        return method.invoke(target,args);
    }
 
    public static void main(String[] args) {
        MyInvoke myInvoke = new MyInvoke(new Hello());
        IHello iHello = (IHello) Proxy.newProxyInstance(MyInvoke.class.getClassLoader(),new Class[]{IHello.class},myInvoke);
        iHello.test();
        iHello.test1();
    }
}

Put the above Hello类 In test1方法 Put in test方法 Medium


    public void test() {
        test1();
        System.out.println("test");
    }

Going back to the above question, you will find that trance1() There is no proxy, so both operations are inserted into the database.
You need to get the current proxy object and call trance1()
Pass AopContext.currentProxy() Get the current agent


 ((UserService)AopContext.currentProxy()).trance1();

Change to call like this trance1()
Run Test, and then there is only one piece of data left in the database, indicating that trance1() Method is rolled back.

The above is the analysis of Springboot nested transaction failure reasons detailed explanation of the details, more on Springboot nested transaction failure analysis of information please pay attention to other related articles on this site!


Related articles: