mysql lock in share mode 容易死锁

本文探讨了JPA+Hibernate中LockModeType.PESSIMISTIC_READ锁机制的应用场景及潜在的死锁问题。通过两个实验案例,展示了在不同情况下如何触发死锁,并深入解析其背后的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JPA+Hibernate 锁 LockModeType.PESSIMISTIC_READ,容易出现死锁的情况,资料记录


情景一

LOCK IN SHARE MODE is not a good solution because if two users read the counter at the same time, at least one of them ends up in deadlock when it attempts to update the counter

如果两个客户端(事务)同时执行同一个查询,都进行更新时,至少其中一个会已死锁结束


实验: 开启两个mysql客户端


1 分别执行如下语句;


set autocommit=0;

begin;

 select * from test_concurrence where id='1' lock in share mode;





可以看到两个客户端都可以查询出数据,不用阻塞等待;


2 分别 执行更新语句


update test_concurrence set name='namelock2111' where id='1';


update test_concurrence set name='namelock3333' where id='1';




检测到死锁,其中一个客户端更新失败,一个执行更新


3 分别执行  commit ,提交事务。


情景二

SELECT ... LOCK IN SHARE MODE: 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.


实验: 开启两个mysql 客户端


1  客户端1执行下面语句

begin;

 select * from test_concurrence where id='1' lock in share mode;

update test_concurrence set name='namelock2' where id='1';

 客户端2 执行


begin;

 select * from test_concurrence where id='1' lock in share mode;





可以看到客户端2 处于等待状态;


2 客户端1提交事务,执行“commit”;





客户端1事务提交成功,客户端3成功查询出数据。



答案


If there is another transaction, that has modified the row, the SELECT ... LOCK IN SHARE MODE waits. If the row is not modified, it does not wait. Which leads to the first situation, that 2 transaction can SELECT ... LOCK IN SHARE MODE, but none of them can update the record (deadlock)


如果有一个事务已经修改了记录数据,另一个事务执行“SELECT ... LOCK IN SHARE MODE ” 语句,则会等待;如果记录数据没有被修改,“SELECT ... LOCK IN SHARE MODE ” 不会等待,从而导致情景一,两个事务都可以成功执行“SELECT ... LOCK IN SHARE MODE”,但是会导致死锁。





参考链接:



http://stackoverflow.com/questions/6607006/select-lock-in-share-mode


http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html

<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]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值