• 数据库新增了一条数据,但是查询不到,是代码玄学么?


    一、背景  

      今天遇到了一个很奇葩的bug,是这样的。我在一个service里面执行了4步操作(流程图如下):

      1)给表1新增了一条数据;

      2)根据表1新增的结果,给表2新增一条数据;

      3)根据表2插入的结果,异步调用第三方接口。然后他们处理完了之后以MQ的形式告诉我的服务;

      4)如果调用第三方接口成功,继续处理剩下的逻辑。

      

      遇到的问题是:我收到第三方的MQ后,有时查表1中新增的数据查不到,但是数据库里面明明有的啊。另外,为啥偶尔查不到呢?难道有代码玄学在作怪么?

      

    二、原因

      究其原因,是 数据库事务在作怪,也怪我当初学习的时候只是背了概念,没有深刻的去理解它。当时代码上面有有一个注解@Transactional,看了它的源码,不声明隔离级别时,它是使用数据库默认的隔离级别。我们知道mysql默认的隔离级别时“可重复读” (读未提交——读已提交——可重复读——串行化)。所以就清楚了,当收到第三方的MQ之后,由于之前的事务没有提交,所以当然查不到数据了。

    @Transactional(rollbackFor = {RuntimeException.class, OptimusExceptionBase.class})
    @Override
    public void xxx(){
      //逻辑处理
    }
    /**
       * Use the default isolation level of the underlying datastore.
       * All other levels correspond to the JDBC isolation levels.
       * @see java.sql.Connection
       */
    Isolation isolation() default Isolation.DEFAULT;

    三、解决办法

      方案一:在收到MQ的那个service里面,可以将隔离级别设置为“读未提交”;

      方案二:在调用第三方的那个service里面,去掉事务,这样只要有数据库的“写操作”,则立马会得到数据库的响应,不会受后续代码写数据库的影响,完全是单独的。当然缺点是需要自己控制事务的执行与回滚;

      方案三:可能情况下,调整代码流程,将调用第三方的操作放在最后,调用第三方结束则方法结束。

    四、其他情况

      还有一种情况也会发生“插入数据,读取不到”。当数据库配置了读写分离后,写数据库会写主库,而读数据会读从库。这样在网络延迟比较高的情况下,可能发生主从延迟——在主库新插入的数据还没有同步到从库,导致查询从库查询不到。对于这种问题,解决办法就好多了,具体用那种根据自己的业务决定:

      1)降低主从延迟;

      2)优化代码逻辑,为啥插入了还要读取;

      3)开启半同步复制,即数据同步到了从库才算真正的插入。

    在全栈的道路上,积极向上、成熟稳重、谦虚好学、怀着炽热的心向前方的走得更远。
  • 相关阅读:
    知识点:Mysql 索引优化实战(3)
    知识点:Mysql 索引原理完全手册(2)
    知识点:Mysql 索引原理完全手册(1)
    大数据体系:数据分析体系总图
    数据化分析:微信文章不增粉的主要原因
    提问:MicrosoftUnderlying input stream returned zero bytes
    优化:更优雅的异步代码?
    涨姿势:Mysql 性能优化完全手册
    总结:Java 集合进阶精讲1
    冷知识点:COLLATE 关键字是什么意思?
  • 原文地址:https://www.cnblogs.com/DDgougou/p/13257265.html
Copyright © 2020-2023  润新知