日常Bug排查-MVCC和for update混用导致读数据不一致

日常Bug排查-MVCC和for update混用导致读数据不一致

前言

日常Bug排查系列都是一些简单Bug的排查。笔者将在这里介绍一些排查Bug的简单技巧,同时顺便积累素材。

Bug现场

又是喜闻乐见的读数据不一致的问题。这次的问题是这样,业务在一个事务中更新A和B两个表的两个数据。但是在另一个事务中只看到了A的更新,而B依旧是更新之前的值。说好的原子性感觉又被打破了。如下图所示:

思路

在将这两个请求的SQL按照时序画出来的时候,笔者立马就明白了相关问题所在。核心就在于数据库是RR隔离级别的,同时业务在查询A的时候使用的是Select for update,在查询B的时候使用的是普通的Select。这么使用的原因可能是觉得所有的查询都需要先查A再查B,那么只需要对A加锁就行,减少了数据库锁的数量。

但是,这里是有一个问题的,就是对B表的查询用的是普通的Select,也就是使用了MySQL的MVCC机制。而MySQL MVCC的默认创建时刻就是事务的第一个不带for update的普通Select(具体原理见笔者的博客https://my.oschina.net/alchemystar/blog/1927425)。那么我们就可以从上面的SQL顺序可以看到,在事务1开始之前就已经创建了视图,此时的视图是A1和B1。那么由于RR,查询B表的普通Select看到的自然是B1,而select for update不走MVCC,于是看到的是A2。如下图所示:

解决方案

让业务对B表的查询也用Select for update即可,相比于不一致增加的一点非热点行锁的性能可以忽略不计。

总结

MVCC和数据库锁两者采用了不同的机制,如果不清楚其中的原理可能会导致不一致的现象出现。同时,在这次的问题中业务对于B表不用锁这样的优化实际上是一个负优化。这再次提醒我们,不要过早优化!

相关推荐
数据龙傲天5 分钟前
1688商品API接口:电商数据自动化的新引擎
java·大数据·sql·mysql
engineer-gxd40 分钟前
MySQL 表的操作
mysql
cyt涛1 小时前
MyBatis 学习总结
数据库·sql·学习·mysql·mybatis·jdbc·lombok
看山还是山,看水还是。2 小时前
MySQL 管理
数据库·笔记·mysql·adb
momo小菜pa2 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke3 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
小宇成长录3 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.4 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构
权^5 小时前
MySQL--聚合查询、联合查询、子查询、合并查询(上万字超详解!!!)
大数据·数据库·学习·mysql
万事大吉CC8 小时前
mysql单表查询·3
数据库·mysql