zoukankan      html  css  js  c++  java
  • 关于java同一个类互相调用,spring事务失效问题

    记录一次上线以后出现异常数据库事务不会滚的情况

    情况:接手别人祖传代码,代码的逻辑 就是定时任务 中更新数据库操作,在更新数据库操作时候出现了异常,但是数据库没有回滚,导致的情况就是数据库数据不一致了!!!

    模拟当时代码情况,定时任务是60s检测更新一次,因为事务失效,导致添加了很多重复数据

    @Service
    public class TestTransactionService {
    
        @Autowired
        public TestTransactionMapper testTransactionMapper;
    
    
        @Scheduled(cron = "*/1 * * * * ?")
        public void callerMethod(){
            calledMethod();
    
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void calledMethod(){
    
            //模拟.......很多表的更新添加等业务逻辑
    
            Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
            TestTransaction name = TestTransaction.builder()
                    .name(integer + "次更新")
                    .build();
            testTransactionMapper.insert(name);
    
            System.out.printf("更新成功:");
    
            System.out.printf(""+1/0);
        }
    }

    解决办法:

    1.最简单的办法就是在调用callerMethod() 上面 加入注解@Transactional(rollbackFor = Exception.class)

    @Service
    public class TestTransactionService {
    
        @Autowired
        public TestTransactionMapper testTransactionMapper;
        
    
        @Transactional(rollbackFor = Exception.class)
        @Scheduled(cron = "*/1 * * * * ?")
        public void callerMethod(){
            calledMethod();
    
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void calledMethod(){
    
            //模拟.......很多表的更新添加等业务逻辑
    
            Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
            TestTransaction name = TestTransaction.builder()
                    .name(integer + "次更新")
                    .build();
            testTransactionMapper.insert(name);
    
            System.out.printf("更新成功:");
    
            System.out.printf(""+1/0);
        }
    }

    2.在当前类中注入自己代码如下:

    @Service
    public class TestTransactionService {
    
        @Autowired
        public TestTransactionMapper testTransactionMapper;
    
        @Autowired
        public TestTransactionService testTransactionService;
    
        @Scheduled(cron = "*/1 * * * * ?")
        public void callerMethod(){
            testTransactionService.calledMethod();
    
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void calledMethod(){
    
            //模拟.......很多表的更新添加等业务逻辑
    
            Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
            TestTransaction name = TestTransaction.builder()
                    .name(integer + "次更新")
                    .build();
            testTransactionMapper.insert(name);
    
            System.out.printf("更新成功:");
    
            System.out.printf(""+1/0);
        }
    }
    

    3.调用代理类的方式

    @Service
    public class TestTransactionService {
    
        @Autowired
        public TestTransactionMapper testTransactionMapper;
    
    
        @Transactional(rollbackFor = Exception.class)
        @Scheduled(cron = "*/1 * * * * ?")
        public void callerMethod(){
            TestTransactionService t=   (TestTransactionService) AopContext.currentProxy();
    
            t.calledMethod();
        }
    
        @Transactional(rollbackFor = Exception.class)
        public void calledMethod(){
    
            //模拟.......很多表的更新添加等业务逻辑
    
            Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
            TestTransaction name = TestTransaction.builder()
                    .name(integer + "次更新")
                    .build();
            testTransactionMapper.insert(name);
    
            System.out.printf("更新成功:");
    
            System.out.printf(""+1/0);
        }
    }
    

     记得还有一种方法是不需要在启动类加的

    如果启动程序的时候报错:Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.

    需要在启动类加上:@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

    4.将需要调用的方法,单独写到另一个Service中,在通过注入该Service进行调用

    记录这次线上的一次问题

    在同一个类中 spring事务是AOP 动态代理实现,一个类中 方法调用是不走代理,只记录问题 分析原因可以从事务的传播机制,以及事务的实现方法着手!!!!

  • 相关阅读:
    CentOS在线安装RabbitMQ3.7
    php redis的GEO地理信息类型
    (PHP)redis Zset(有序集合 sorted set)操作
    (PHP)redis Set(集合)操作
    (PHP)redis Hash(哈希)操作
    (PHP)redis List(列表)操作
    php cURL error 60
    go build 不同系统下的可执行文件
    windows下改变go的gopath
    线程池简要学习[转]
  • 原文地址:https://www.cnblogs.com/920913cheng/p/15744377.html
Copyright © 2011-2022 走看看