MySQL REPEATABLE-READ隔离级别实战:利用受影响的行数判断更新是否生效
在MySQL的REPEATABLE-READ(可重复读)隔离级别下,事务内的SELECT操作具有快照一致性,不会读到其他事务已提交的修改。但UPDATE操作的执行结果却依赖于当前锁的状态和行版本号。本文通过多会话并发操作实例,解析如何利用UPDATE语句返回的“Affected rows”(受影响行数)是否为0,来判断目标记录的状态是否已被其他事务抢先修改,这是一种在高并发场景下判断更新是否成功的有效策略。
结果或目标
理解MySQL REPEATABLE-READ 隔离级别下数据可见性与行更新的机制,掌握通过Affected rows返回值判断业务状态变更的方法。
准备条件
- MySQL数据库环境(默认隔离级别即为
REPEATABLE-READ)。 - 测试表结构,例如:
CREATE TABLE test.dd (id INT PRIMARY KEY, aa INT);。 - 两个独立的数据库客户端连接,分别代表“会话1”和“会话2”。
真实操作顺序
第1步:开启会话1的事务并禁用自动提交
目的:创建一个稳定的查询视图,确保后续SELECT读取的是事务开始时的快照数据。
入口:客户端1(会话1)。
动作:设置自动提交关闭,防止中间操作立即写入磁盘,保持事务状态。
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
第2步:会话1读取基准数据
目的:获取初始状态数据,作为后续对比的基准。
入口:客户端1(会话1)。
动作:执行SELECT查询。
mysql> select * from test.dd where id=1;
+----+------+
| id | aa |
+----+------+
| 1 | 2 |
+----+------+
1 row in set (0.00 sec)
完成状态:确认当前 aa 字段的值为 2。
第3步:会话2修改数据并提交
目的:模拟另一个事务对同一行数据进行更新并永久化该更改。
入口:客户端2(会话2)。
动作:将 id=1 的记录中 aa 字段从 2 更新为 1,并提交事务。
-- 会话2
mysql> update test.dd set aa=1 where id=1;
Query OK, 1 row affected (0.09 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> commit;
第4步:会话1验证快照一致性
目的:证明在REPEATABLE-READ隔离级别下,未重启事务前,SELECT依然看到旧数据。
入口:客户端1(会话1)。
动作:再次执行相同的SELECT查询。
mysql> select * from test.dd where id=1;
+----+------+
| id | aa |
+----+------+
| 1 | 2 |
+----+------+
1 row in set (0.00 sec)
观察:尽管会话2已经提交了 aa=1 的更改,但会话1依然读到 aa=2。这是MVCC(多版本并发控制)提供的快照读特性。
第5步:会话1尝试更新并观察受影响行数
目的:核心步骤。演示当基于旧快照数据执行UPDATE时,如果底层数据已被他人修改,会发生什么。
入口:客户端1(会话1)。
参数:尝试将 aa 从 2 更新为 1(与会话2最终值一致,但原始值是2)。
mysql> update test.dd set aa=1 where id=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
关键结果:显示 0 rows affected。
原理分析与完成判断
为什么SELECT读到的是 2,UPDATE却显示影响了0行?
- 快照读 vs 当前读:SELECT是快照读,看到的是事务开始时的版本;而UPDATE是当前读,它必须锁定并查看最新的数据版本以确定是否真的需要改变值。
- 更新逻辑:InnoDB在执行
UPDATE test.dd SET aa=1 WHERE id=1时,会检查当前数据库文件中aa的实际值。由于会话2已经将其改为1,而UPDATE语句的目标值也是1,即“新值等于旧值”,因此InnoDB判定无需进行物理层面的数据页修改。 - 受影响行数(Changed Rows):只有在数据库引擎真正修改了行的内容时,“Changed”才会增加。若新旧值相同,虽然匹配了WHERE条件(Matched=1),但实际未发生变更(Changed=0)。
简要总结
在开发涉及状态位(如订单状态、库存扣减校验)的逻辑时,直接相信SELECT的结果可能存在风险(因为SELECT可能读到过期快照)。更稳健的做法是利用REPEATABLE-READ特性,执行UPDATE操作,并严格检查其返回的Affected rows:
- 若为
1:说明该行曾被修改且确实发生了数值变化,或者此前从未存在被正确更新。 - 若为
0:结合业务逻辑,通常意味着该行数据已被其他事务抢先修改到了目标值,或者当前事务持有的数据版本与数据库现实不符导致无需/不能更新。
以上方法在处理高并发竞争条件时,是一种简洁且有效的乐观锁实现思路。
以上就是MySQL REPEATABLE-READ隔离级别下利用UPDATE受影响行数判断更新状态的详细内容,更多关于MySQL事务控制与并发优化的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









