美文网首页
13 Springboot中嵌套事务失效原因分析

13 Springboot中嵌套事务失效原因分析

作者: lijiaccy | 来源:发表于2017-12-25 15:59 被阅读0次

    前两天看了一个视频,忘了谁讲的,主要讲的是嵌套事务失效的问题。正好我也遇到了
    还是用上一个例子,代码放在最后了。

    首先两个事务方法,其中一个调用另一个。

    @Transactional(rollbackFor = Exception.class)
    public void trance() {
        try {
            trance1();//调用下一个事务方法。
        } 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();
    }
    

    添加依赖
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    然后写个测试类,我也是第一次用这个测试

    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();
        }
    }
    

    执行会发现报了RuntimeException,但是数据库里面有两条数据,说明事务失效了

    runtimeException
    数据库两条数据都上传了,说明事务失效
    为什么会出现这种情况呢
    spring事务使用了动态代理。还是从动态代理去看。
    给出一段代码
    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("========代理了=======");
            }
            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();
        }
    }
    

    运行结果是


    将上面的Hello类中的test1方法放入test方法
        public void test() {
            test1();
            System.out.println("test");
        }
    

    回到上面的问题,会发现trance1()没有走代理,所以会出现两个都插入数据库的操作。
    那么需要得到当前的代理对象,然后调用trance1()
    通过AopContext.currentProxy()获得当前代理
     ((UserService)AopContext.currentProxy()).trance1();
    

    改成这样调用trance1()
    运行Test,然后数据库就剩一条数据了,说明trance1()方法回滚了。

    还是原来的代码: https://github.com/lijiaccy/springboot-sharding-table

    相关文章

      网友评论

          本文标题:13 Springboot中嵌套事务失效原因分析

          本文链接:https://www.haomeiwen.com/subject/nhplgxtx.html