@DSTransactional无效问题记录

记录下项目遇到的问题,供参考。

项目使用了多数据源,使用@DS来选择要操作的数据源,使用@DSTransactional来控制事务

@DSTransactional原理:定义一个方法拦截器 ,将有@DSTransactional的方法搞到Advisor里,再由Spring Aop来扫进容器,当执行方法的时候,会执行拦截逻辑,进行事务提交或回滚操作。

涉及的类:

DynamicLocalTransactionInterceptor :方法拦截,增加事务控制

DynamicDataSourceAutoConfiguration:配置,定义一些bean,被Spring扫描

DynamicDataSourceAnnotationAdvisor:将有注解的方法(@DSTransactional,@DS),增加方法拦截器

事务方法拦截源码(DynamicLocalTransactionInterceptor )

@Slf4j
public class DynamicLocalTransactionInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        if (!StringUtils.isEmpty(TransactionContext.getXID())) {
            return methodInvocation.proceed();
        }
        boolean state = true;
        Object o;
        LocalTxUtil.startTransaction();
        try {
            o = methodInvocation.proceed();
        } catch (Exception e) {
            state = false;
            throw e;
        } finally {
            if (state) {
                LocalTxUtil.commit();
            } else {
                LocalTxUtil.rollback();
            }
        }
        return o;
    }
}

配置类(DynamicDataSourceAutoConfiguration)实现DS、DSTransactional这两个注解

    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean
    @ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX + ".aop", name = "enabled", havingValue = "true", matchIfMissing = true)
    public Advisor dynamicDatasourceAnnotationAdvisor(DsProcessor dsProcessor) {
        DynamicDatasourceAopProperties aopProperties = properties.getAop();
        DynamicDataSourceAnnotationInterceptor interceptor = new DynamicDataSourceAnnotationInterceptor(aopProperties.getAllowedPublicOnly(), dsProcessor);
        DynamicDataSourceAnnotationAdvisor advisor = new DynamicDataSourceAnnotationAdvisor(interceptor, DS.class);
        advisor.setOrder(aopProperties.getOrder());
        return advisor;
    }

    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    @Bean
    @ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true)
    public Advisor dynamicTransactionAdvisor() {
        DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor();
        return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class);
    }

我的代码,事务无效

@Service
public class MyService{
    public void save() {
        insert();
    }

    @DSTransactional
    public void insert() {
        insertMom();
        insertWms();
    }

    public void insertMom() {
        // mapper.insert
    }

    public void insertWms() {
        // mapper.insert
    }
}

修改后(自己注入自己,因为Spring本身解决了循环依赖的问题,所有没问题)

@Service
public class MyService{

    @Autowired
    private MyService service;

    public void save() {
        service.insert();
    }

    @DSTransactional
    public void insert() {
        insertMom();
        insertWms();
    }

    public void insertMom() {
        // mapper.insert
    }

    public void insertWms() {
        // mapper.insert
    }
}

原因:Spring的AOP不支持是方法内直接调用,参考:

https://blog.csdn.net/vcj1009784814/article/details/116049314​​​​​​

另外, 方法非public,事务也是无效的;内部吃掉异常这个不多说,@Transactional一样

总结:

        @DSTransactional和@Transactional一样,存在事务失效的场景,如下

        1、非代理类调用@DSTransactional的方法(自己注入自己,也可以通过其他方式拿到容器中的Bean)

        2、方法非public

        3、异常没到注解,被方法内部吃掉try-catch

你可能感兴趣的:(MyBatis之路,mybatis,数据库)