MySQL5.7 InnoDB下select与update访问同记录的锁机制问题咨询
MySQL 5.7 InnoDB 锁行为场景解答
以下结论基于MySQL 5.7 默认参数配置的InnoDB引擎,默认隔离级别为可重复读(REPEATABLE READ),默认开启MVCC(多版本并发控制),所有提到的select均为普通无锁查询,更新操作均为题目描述的基于主键的精准更新。
场景1:读操作执行过程中并发更新同一条记录
- 结论:两个操作无需互相等待,可以正常并发执行。
- 锁机制具体表现:
- InnoDB的普通select属于快照读,不会对数据加任何行锁/表锁,而是通过读取undo log中存储的历史版本数据来获取一致性结果。
- 执行update的线程只会给目标行加X型排他行锁,这类锁仅会阻塞其他需要加锁的操作(比如其他针对同一行的update/delete、
select ... for update/select ... lock in share mode),不会阻塞普通快照读。 - 读线程不会感知到更新线程加的行锁,直接读取历史版本即可,更新线程也不会被读操作阻塞,拿到行锁后即可完成字段更新。
场景2:批量更新执行过程中并发查询同一条记录
- 结论:默认配置下两个操作无需互相等待,可以正常并发执行。
- 锁机制具体表现:
- 批量更新线程基于主键定位需要修改的10000条记录,会逐行给目标行加X型排他行锁,更新完成后生成新的数据版本,修改前的旧版本会保留在undo log中。
- 执行select的线程依旧走MVCC快照读逻辑,不需要申请任何数据锁,会根据自身事务的一致性视图从undo log中读取匹配的历史版本数据:如果select事务启动在批量更新事务提交前,就会读到更新前的字段值;如果启动在批量更新事务提交后,就会读到更新后的null值。
- 仅当select为加锁读时,才会等待批量更新线程释放对应行的X锁,出现阻塞等待的情况。
补充说明
因为更新操作是基于主键执行的精准匹配,不会出现全表扫描的情况,InnoDB只会给实际需要更新的行加行锁,不会加gap锁(间隙锁)也不会锁全表,不会影响该表其他行的读写操作。
内容的提问来源于stack exchange,提问作者jithin giri
相关产品推荐
相关产品推荐

