2022年8月更文挑战11-@Transactional注解在方法间调用

81 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第11天,点击查看活动详情

@Transactional注解在方法间调用

前文

在@Transactional注解的使用中,经常会遇到需要在方法间调用的情况。当在不同方法间进行调用时,经常会出现事务失败的情况。本文将针对该注解在方法间的调用相关内容进行总结。

在方法中如何进行@Transactional注解调用

下面根据不同的调用方式,分析该注解的生效及不生效情况。

  • 在直接调用的方法上直接添加注解,在被调用的方法上不加注解
@Transactional(rollbackFor = Exception.class)
    public Object test() {
        this.test1();
//        applicationContext.getBean(TestTransactionalService.class).test1();
        return "success";
    }

//    @Transactional(rollbackFor = Exception.class)
    public Object test1() {
        TestTransactionalPO testTransactionalPO = new TestTransactionalPO();
        testTransactionalPO.setId(3L);
        testTransactionalPO.setName("a");
        testTransactionalMapper.addData(testTransactionalPO);
        throw new RestApiException(ExceptionInfoEnum.DATA_NOT_FOUND_EXCEPTION);
    }

这种方式事务生效,也就是只要我们在通过bean直接调用的对象方法上增加注解,即可完成回滚。使用this调用时采用的依然是被切面包装过的对象。

  • 在直接调用的方法上加注解,在被调用的方法上加注解
@Transactional(rollbackFor = Exception.class)
    public Object test() {
        this.test1();
//        applicationContext.getBean(TestTransactionalService.class).test1();
        return "success";
    }

    @Transactional(rollbackFor = Exception.class)
    public Object test1() {
        TestTransactionalPO testTransactionalPO = new TestTransactionalPO();
        testTransactionalPO.setId(3L);
        testTransactionalPO.setName("a");
        testTransactionalMapper.addData(testTransactionalPO);
        throw new RestApiException(ExceptionInfoEnum.DATA_NOT_FOUND_EXCEPTION);
    }

在bean直接调用的方法上使用注解,同时在被调用的方法上使用注解,该事务同样是生效的。由于事务的传播机制,按照默认的方法,这种情况下两者的注解采用的是相同的事务。

  • 在直接调用的方法不加注解,在被调用的方法上增加注解
public Object test() {
        this.test1();
//        applicationContext.getBean(TestTransactionalService.class).test1();
        return "success";
    }

    @Transactional(rollbackFor = Exception.class)
    public Object test1() {
        TestTransactionalPO testTransactionalPO = new TestTransactionalPO();
        testTransactionalPO.setId(3L);
        testTransactionalPO.setName("a");
        testTransactionalMapper.addData(testTransactionalPO);
        throw new RestApiException(ExceptionInfoEnum.DATA_NOT_FOUND_EXCEPTION);
    }

在bean直接调用方法上不使用注解,而在被调用的方法上使用注解。如果我们采用this进行调用,事务是不生效的。而如果我们采用applicationContext.getBean(TestTransactionalService.class)的方式获取bean对象,再进行调用,则该事务是生效的。原因是实际的该注解是作用在动态代理对象上的,如果我们采用this直接调用并非动态代理对象,也就会导致注解失效。cache、aop等都存在该问题。

额外补充

在多线程的应用场景下,该注解是不生效的。如果多线程需要进行事务回滚操作,需要我们在代码内手动进行回滚。

后记

  • 千古兴亡多少事?悠悠。不尽长江滚滚流。