MySQL中的行级锁SELECT FOR UPDATE 和LOCK IN SHARE MODE 区别

本文详细介绍了MySQL中SELECT...LOCK IN SHARE MODE与SELECT...FOR UPDATE两种事务锁的使用方式及特点。前者为共享锁,允许其他会话读取锁定的数据但不能进行修改;后者为排他锁,阻止其他会话对锁定数据进行读写操作。

自己记录一下,加深一下印象。英文资料来自于MySQL的官方文档。中文为自己按照理解翻译的。

      SELECT ... LOCK IN SHARE MODE sets a shared mode lock on the rows read. A shared mode lock enables other sessions to read the rows but not to modify them. The rows read are the latest available, so if they belong to another transaction that has not yet committed, the read blocks until that transaction ends.
在读取的行上设置一个共享模式的锁。这个共享锁允许其它session读取数据但不允许修改它。 行读取的是最新的数据,如果他被其它事务使用中而没有提交,读取锁将被阻塞知道那个事务结束。


      SELECT ... FOR UPDATE sets an exclusive lock on the rows read. An exclusive lock prevents other sessions from accessing the rows for reading or writing.
在读取行上设置一个排他锁。组织其他session读取或者写入行数据
<think>嗯,用户这次的问题非常具体,聚焦在MySQL RR隔离级别下使用LOCK IN SHARE MODE是否会加间隙锁。看来用户对数据库锁机制有深入研究的需求,可能是遇到实际开发中的并发控制问题了。 从用户引用的资料来看,ta已经做了不少功课,特别是引用[1]明确提到Serializable级别会加间隙锁,而引用[4][5]指出InnoDB的RR级别通过MVCC+锁机制解决幻读问题。用户可能正在设计高并发系统,需要精确控制锁行为。 我注意到用户特别强调"参考站内引用",说明ta希望答案有明确依据。结合引用[1]的RR隔离级别说明引用[3]的共享锁解释,可以确认LOCK IN SHARE MODE在RR级别确实可能触发间隙锁。但需要区分两种情况:当查询使用唯一索引精确匹配时通常只加记录锁,而范围查询或非唯一索引时就会加间隙锁。 用户似乎对幻读问题特别关注,这很合理。因为RR级别虽然通过MVCC解决快照读的幻读,但当前读(如LOCK IN SHARE MODE)仍需依赖间隙锁防止幻读。引用[5]正好佐证了这点,说明MVCC不能解决当前读的幻读问题。 回答时要特别注意技术细节的准确性。比如要强调间隙锁的触发条件与索引类型、查询条件密切相关。可以举两个对比例子:where id=1(唯一索引精确值) vs where age=20(非唯一索引)。前者只加记录锁,后者可能加间隙锁。 用户可能还会关心锁冲突问题,所以在回答最后补充了死锁风险提示。考虑到ta的技术水平,建议提供具体监控方法,比如show engine innodb status命令查看锁状态。</think>在MySQL的**RR(可重复读)隔离级别**下,使用`LOCK IN SHARE MODE` **是否加间隙锁取决于查询条件**: ### 关键结论 1. **唯一索引的精确匹配查询** ```sql SELECT * FROM table WHERE unique_col = 1 LOCK IN SHARE MODE; ``` - **不加间隙锁** 仅对匹配的行加**共享记录锁(S锁)**,因为唯一索引可确保无幻读风险[^1][^4]。 2. **非唯一索引或范围查询** ```sql SELECT * FROM table WHERE non_unique_col = 2 LOCK IN SHARE MODE; ``` - **会加间隙锁** InnoDB 会在匹配行及相邻间隙加**共享间隙锁(S Gap Lock)**,防止其他事务在锁定范围内插入新数据,从而解决幻读问题[^1][^4][^5]。 --- ### 底层机制分析 1. **RR隔离级别的锁策略** - InnoDB 在 RR 级别通过 **MVCC(多版本并发控制)** 解决快照读的幻读问题。 - 但对**当前读**(如 `LOCK IN SHARE MODE`、`FOR UPDATE`),需依赖 **间隙锁** 阻止幻读[^4][^5]。 2. **间隙锁的触发条件** | 查询类型 | 索引类型 | 是否加间隙锁 | |------------------------|---------------|--------------| | 精确查询(`= 1`) | **唯一索引** | ❌ 否 | | 精确查询(`= 1`) | **非唯一索引**| ✅ 是 | | 范围查询(`BETWEEN`) | 任意索引 | ✅ 是 | 3. **锁冲突示例** - 事务A执行: ```sql SELECT * FROM users WHERE age = 20 LOCK IN SHARE MODE; -- 非唯一索引 ``` - 事务B尝试插入: ```sql INSERT INTO users (age) VALUES (20); -- 被阻塞(间隙锁生效) ``` --- ### 不同隔离级别的对比 | 隔离级别 | `LOCK IN SHARE MODE` 行为 | |----------------|-------------------------------------| | **RR(默认)** | 非唯一索引/范围查询时加间隙锁 | | **RC** | 永不加间隙锁(仅加记录锁)[^4][^5] | | **Serializable**| 所有查询强制加间隙锁(等效表锁)[^1] | > **提示**:可通过 `SHOW ENGINE INNODB STATUS` 查看锁信息,确认间隙锁是否生效。 --- ### 总结 - ✅ **加间隙锁的场景**: RR 隔离级别下,若查询使用**非唯一索引**或**范围条件**,`LOCK IN SHARE MODE` 会触发间隙锁。 - ❌ **不加间隙锁的场景**: 查询使用**唯一索引精确匹配**时,仅加行级共享锁。 设计高并发系统时,建议通过**优化索引**(尽量用唯一索引)减少间隙锁冲突,或评估是否可降级到 **RC 隔离级别**[^4][^5]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值