MySQL中FOR UPDATE锁是否允许其他连接执行普通SELECT语句查询?
关于MySQL SELECT ... FOR UPDATE加锁后普通SELECT是否可读取的问题解答
问题1:未显式开启事务的普通SELECT能否读取被FOR UPDATE加锁的记录?
默认配置下(InnoDB引擎,事务隔离级别为可重复读RR/读提交RC),完全可以读取,不会被阻塞。
原因是InnoDB的普通无锁SELECT默认属于快照读,基于MVCC(多版本并发控制)机制实现,只会读取记录在undo log中保存的历史版本,不会申请读取目标行的锁资源,所以完全不会和其他事务持有的FOR UPDATE排他锁产生冲突。
问题2:“默认隐式事务下普通SELECT无法读取被FOR UPDATE锁定的记录”这一结论是否正确?
该结论错误,属于对隐式事务和InnoDB读逻辑的混淆。
首先明确两个核心概念:
- 隐式事务的生效范围:仅针对需要加锁的当前读操作生效,包括
SELECT ... FOR UPDATE、SELECT ... LOCK IN SHARE MODE、INSERT、UPDATE、DELETE等,这类操作需要读取记录的最新版本,并且需要申请对应锁资源,才会触发锁冲突阻塞。 - 普通SELECT属于快照读,不涉及锁申请逻辑,和是否为隐式事务没有关联,无论是否显式开启事务,都不会被其他事务的FOR UPDATE锁阻塞。
唯一例外场景
只有当事务隔离级别调整为**串行化(SERIALIZABLE)**时,InnoDB会自动将普通无锁SELECT转换为SELECT ... LOCK IN SHARE MODE的共享锁当前读,这种场景下普通SELECT才会被其他事务持有的FOR UPDATE排他锁阻塞,该配置不属于MySQL默认配置。
本地验证方法
你可以通过两个MySQL客户端快速验证结论:
- 客户端A执行加锁操作不提交:
START TRANSACTION; -- 假设test表存在id=1的记录 SELECT * FROM test WHERE id = 1 FOR UPDATE;
- 客户端B直接执行普通查询:
SELECT * FROM test WHERE id = 1;
执行后可以直接拿到查询结果,不会出现阻塞。
内容的提问来源于stack exchange,提问作者Neidi
相关产品推荐
相关产品推荐

