Kafka事务导致Spring事务不生效

1. 工程环境

SpringBoot: 2.2.6.RELEASE
Mybatis-plus: 3.3.0

2. 发现问题

    @Transactional(rollbackFor = Exception.class)
    public Boolean saveTemplate(VoucherTemplateEntity voucherTemplateEntity, List groupEntityList,
                                List targetEntityList, List criterionEntityList,
                                List ruleEntityList, List rightEntityList, List noticeList) {
        //保存分组
        if(CollectionUtils.isNotEmpty(groupEntityList)){
            voucherGroupMapper.batchInsert(groupEntityList);
        }
        //保存目标人群
        if(CollectionUtils.isNotEmpty(targetEntityList)){
            voucherTargetMapper.batchInsert(targetEntityList);
        }
        //保存生效规则
        if(CollectionUtils.isNotEmpty(criterionEntityList)){
            voucherCriterionMapper.batchInsert(criterionEntityList);
        }
        //保存使用规则
        if(CollectionUtils.isNotEmpty(ruleEntityList)){
            voucherRuleMapper.batchInsert(ruleEntityList);
        }
        //保存权益
        if(CollectionUtils.isNotEmpty(rightEntityList)){
            voucherRightMapper.batchInsert(rightEntityList);
        }
        if(CollectionUtils.isNotEmpty(noticeList)){
            voucherNoticeMapper.batchInsert(noticeList);
        }
        //保存模板
        voucherTemplateMapper.insert(voucherTemplateEntity);

        throw new NullPointerException();

//        return true;
    }

很普通的事务使用方式,但是发生异常就是不会回滚,百思不得其解。

3. debug过程

加了各种配置:

spring:
  transaction:
    rollback-on-commit-failure: true

@EnableTransactionManagement
统统没用
----------------------分割线--------------------
参考了这篇文章
在这个地方发现了问题!!
org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction
拿到的TransactionManager居然是KafkaTransactionManager !!! WTF??!

TransactionAspectSupport

点进去查看具体的获取tm方法:
determineTransactionManager

也就是当前的对象是kafka的事务管理器,DataSourceTransactionManager去哪里了,没有注入?

一顿分析,查看相关的配置类:


DataSourceTransactionManagerAutoConfiguration

这个地方有个@ConditionalOnMissingBean(PlatformTransactionManager.class)

而KafkaTransactionManager恰好是PlatformTransactionManager子类


KafkaAutoConfiguration

所以默认的TransactionManager就用了KafkaTransactionManager,WTF?这是不是属于Spring的bug

知道了问题就好解决了,百度一下解决方式...

4. 解决方法

参考这个:https://blog.csdn.net/feg545/article/details/113742434
1.要解决DataSourceTransactionManagerAutoConfiguration默认不注册transactionManager的问题
2.让transactionManager变成默认的事务管理器,免得在所有@Transactional指明事务管理器名称
3.要增加一个chainedTransactionManager使得kafka和数据库操作同时在事务中

@Configuration
public class TransactionConfig {
    private final DataSource dataSource;

    private final TransactionManagerCustomizers transactionManagerCustomizers;

    TransactionConfig(DataSource dataSource,
                                              ObjectProvider transactionManagerCustomizers) {
        this.dataSource = dataSource;
        this.transactionManagerCustomizers = transactionManagerCustomizers.getIfAvailable();
    }

    @Bean //去掉了ConditionalOnMissingBean解决问题1
    @Primary  //解决问题2
    public DataSourceTransactionManager transactionManager(DataSourceProperties properties) {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(this.dataSource);
        if (this.transactionManagerCustomizers != null) {
            this.transactionManagerCustomizers.customize(transactionManager);
        }
        return transactionManager;
    }

    @Bean  //解决问题3
    public ChainedKafkaTransactionManager chainedKafkaTransactionManager(DataSourceTransactionManager transactionManager,
                                                               KafkaTransactionManager kafkaTransactionManager){
        return new ChainedKafkaTransactionManager<>(transactionManager, kafkaTransactionManager);
    }
}

最后在启动类加上@Transactional(transactionManager = "chainedKafkaTransactionManager")

PROBLEM SOLVED!

你可能感兴趣的:(Kafka事务导致Spring事务不生效)