关于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 动态代理实现,一个类中 方法调用是不走代理,只记录问题 分析原因可以从事务的传播机制,以及事务的实现方法着手!!!!

 

posted on 2021-12-29 11:47  年少不知愁  阅读(1895)  评论(0编辑  收藏  举报