zoukankan      html  css  js  c++  java
  • 记一次 Spring 事务配置踩坑记

    记一次 Spring 事务配置踩坑记

    问题描述:(SpringBoot + MyBatisPlus)

    业务逻辑伪代码如下。理论上,插入数据 t1 后,xxService.getXxx() 方法的查询条件会不满足,会查询不到数据。结果事与愿违,后一次的查询,居然查到了数据。

    void saveXxx(){
     xxService.getXxx(); // 查到一条数据 data1
     xxService.insert(); // 插入一条数据 t1
     xxService.getXxx(); // 查到一条数据 data1
    }

     

    分析过程:

    抛弃业务逻辑,在一个新的 service 中写了一个最简单的测试,查询 --> 插入 --> 查询。为了保证两者具有可比性,sql 都从原 Mapper 中拷贝过去。但是依然重现不了问题。神奇的是出现了如下的情况:

    @Transactional
    void testMyBatis(){
     yyService.getYyy(); // 查到一条数据 data1
     yyService.insert(); // 插入一条数据 t1
     yyService.getYyy(); // 查不到数据
     xxService.getXxx(); // 查到一条数据 data1
    }

    理论上,yyService.getYyy() 与 xxService.getXxx() 应该都查不到数据才对,结果只有 xxService.getXxx() 能查到。

    开始怀疑事务的问题,是不是 xxService.getXxx() 新开启了一个事务去查询,只有这样,xxService.getXxx() 的查询条件才不受当前事务插入的数据所影响。

    检查项目中的事务配置,除了配置了注解式事务外,还有如下的声明式事务配置:

    @Bean
    public TransactionInterceptor txAdvice() {
    NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
    RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
    readOnlyTx.setReadOnly(true);
    readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );
    RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
    requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
    requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
    requiredTx.setTimeout(TX_METHOD_TIMEOUT);
    Map<String, TransactionAttribute> txMap = new HashMap<>();
    txMap.put("add*", requiredTx);
    txMap.put("save*", requiredTx);
    txMap.put("insert*", requiredTx);
    txMap.put("update*", requiredTx);
    txMap.put("delete*", requiredTx);
    txMap.put("get*", readOnlyTx);
    txMap.put("query*", readOnlyTx);
    source.setNameMap( txMap );
    TransactionInterceptor txAdvice = new TransactionInterceptor(transactionManager, source);
    return txAdvice;
    }

    就是这一行配置搞的鬼:readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED ); get*开头的方法都加了只读事务,而只读事务是以非事务方式运行,如果当前存在事务,则把当前事务挂起。

    这样就解释了为什么 xxService.getXxx() 方法能够查到数据了,它是在当前事务之外查询的数据。

     

    解决办法:

    将 readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED ); 去掉。

    附:还是使用注解式事务吧 ^_^

  • 相关阅读:
    shell 案例
    linux 软链接和硬链接区别
    mac安装使用nginx
    Leetcode SQL_#176_第二高的薪水
    南邮ctf web题记录(上)
    CTFHub Web技能树
    XCTF web 新手练习区
    诊断工具--arthas使用教程
    prometheus--监控工具
    无状态状态机--cola stateMachine
  • 原文地址:https://www.cnblogs.com/kevin-yuan/p/9970765.html
Copyright © 2011-2022 走看看