MySQL中UPDATE自增语句在RR隔离级下的异常行为问询
MySQL RR隔离级下UPDATE语句的行为解析
问题场景
初始user表中id=8的fans值为0,使用MySQL 8.0.41(InnoDB引擎,REPEATABLE-READ隔离级),操作步骤如下:
- 开启事务A,执行
SELECT * fromuserWHERE id = 8;,查询结果fans=0,保持事务未提交; - 开启事务B,执行
UPDATEuserSET fans = fans +1 where id = 8;并提交,此时表中该记录fans=1; - 事务A中再次执行
SELECT * fromuserWHERE id = 8;,结果仍为fans=0,符合RR隔离级预期; - 事务A中执行
UPDATEuserSET fans = fans +1 where id = 8;后,再次查询发现fans=2,提交事务A后最终值为2。
疑问:这是自增语句的特殊设计,还是异常?
技术解析
这不是异常,是InnoDB在REPEATABLE-READ(RR)隔离级下的正常行为,核心原因是快照读与当前读的区别,以及UPDATE语句的执行逻辑:
1. 快照读与当前读的差异
- 普通
SELECT语句在RR隔离级下是快照读:基于事务启动时的一致性快照返回数据,所以事务A两次普通查询都能看到初始的fans=0,符合RR的可重复读特性。 UPDATE语句属于当前读:执行时会直接读取最新的提交版本数据,并且会对目标记录加排他锁。
2. UPDATE语句的执行逻辑
事务A执行UPDATE user SET fans = fans +1 where id = 8;时,流程是:
- 以当前读的方式获取该记录的最新提交版本(即事务B提交后的
fans=1); - 基于这个最新值计算
fans+1,得到2; - 将计算后的值写入事务A的本地快照中;
- 此时事务A内再执行普通
SELECT,会读取自己事务内已修改的快照数据,所以看到的是fans=2。
3. 与RC隔离级的本质区别
RC隔离级下普通查询会直接读取最新提交版本,但这里事务A的普通查询仍然是快照读——只是UPDATE操作触发了当前读并修改了自身快照,后续查询看到的是自己修改后的数据,而非其他事务的提交数据。如果事务A在UPDATE后,其他事务再修改该记录,事务A的普通查询还是看不到外部的修改,这和RC的行为有本质区别。
4. 与自增语句无关
这种行为和fans = fans +1的自增语法没有关系,任何基于当前记录值修改的UPDATE语句(比如fans = fans -1、score = score * 2)都会触发相同逻辑,核心是UPDATE的当前读特性。
内容的提问来源于stack exchange,提问作者Billy
相关产品推荐
相关产品推荐

