0

0

mysql索引和锁之间有什么关系_mysql并发原理说明

P粉602998670

P粉602998670

发布时间:2026-01-20 01:17:34

|

419人浏览过

|

来源于php中文网

原创

MySQL行锁实际是对索引项加锁,无索引或索引失效时会升级为全表扫描并加X锁,等效锁表;InnoDB默认临键锁(记录锁+间隙锁)防幻读,READ COMMITTED可降级为仅记录锁。

mysql索引和锁之间有什么关系_mysql并发原理说明

索引没建好,行锁会自动升级成表锁

MySQL 的行锁不是“对行加锁”,而是“对索引项加锁”。InnoDB 只能通过索引定位数据,如果 WHERE 条件字段没有索引(或索引失效),优化器无法快速定位记录,就会退化为全表扫描——此时为了保证一致性,InnoDB 会为**所有扫描过的记录**加锁;而最坏情况下,它可能对**聚簇索引的每条记录都加 X 锁**,效果等同于锁表。

  • 常见错误现象:UPDATE user SET status=1 WHERE phone='138xxx' 执行极慢、阻塞其他事务,SHOW ENGINE INNODB STATUS 显示大量 lock_mode X locks rec but not gap 且涉及成千上万行
  • 实操建议:执行前先用 EXPLAIN 确认是否走了索引;对高频查询/更新的字段(如 phoneorder_no)务必建立单独索引或作为联合索引的最左前缀
  • 特别注意:LIKE '%abc'OR 混合条件、函数包裹字段(如 WHERE DATE(create_time) = '2025-01-01')都会导致索引失效,触发隐式锁表

为什么加了索引还锁不住“该锁的行”?临键锁(Next-Key Lock)才是默认行为

InnoDB 默认使用 REPEATABLE READ 隔离级别,其行锁实际是 Next-Key Lock(临键锁):即「记录锁 + 间隙锁」的组合。它不仅锁住匹配的索引记录,还会锁住该记录与前一条记录之间的「间隙」,目的是防止幻读。

  • 使用场景:执行 SELECT * FROM order WHERE amount > 100 FOR UPDATE 时,即使表中当前只有 amount=150amount=200 两条记录,InnoDB 也会锁定 (100, 150)、(150, 200)、(200, +∞) 这三个间隙,阻止其他事务插入 amount 在这些范围内的新订单
  • 参数差异:若改用 READ COMMITTED 隔离级别,InnoDB 会退化为只加「记录锁」(Record Lock),不加间隙锁——幻读风险上升,但并发写入能力提升
  • 容易踩的坑:业务以为 SELECT ... FOR UPDATE 只锁查到的几行,结果发现插入操作被莫名阻塞,根源就是临键锁锁住了“不该插的位置”

共享锁(S锁)和排他锁(X锁)的兼容性决定并发读写能否并行

锁的本质是资源访问的互斥协议。InnoDB 中,S 锁SELECT ... LOCK IN SHARE MODE)允许多个事务同时持有,但会阻塞任何 X 锁;而 X 锁SELECT ... FOR UPDATEUPDATE/DELETE)一旦加上,其他事务既不能加 S 锁 也不能加 X 锁

音剪
音剪

喜马拉雅旗下的一站式AI音频创作平台,强大的在线剪辑能力,帮你轻松创作优秀的音频作品

下载
  • 常见错误现象:两个事务先后执行 SELECT ... FOR UPDATE 查询同一行,第二个事务卡住直到第一个提交——这是正常行为;但如果两个事务都只执行 SELECT ... LOCK IN SHARE MODE,则可以并发成功
  • 实操建议:读多写少场景下,优先用 LOCK IN SHARE MODE 替代 FOR UPDATE,减少写冲突;更新前务必确认是否真需要独占锁,避免过度加锁拖慢整体吞吐
  • 性能影响:S 锁之间不互斥,开销远小于 X 锁;但大量 S 锁仍会占用锁结构内存,极端情况下触发 Lock wait timeout exceeded

MVCC 不是“不用锁”,而是让读操作尽量避开锁

MVCC(多版本并发控制)让普通 SELECT(不带 FOR UPDATELOCK IN SHARE MODE)无需加锁,直接读取事务开启时刻的快照版本。但这只对「一致性非锁定读」有效;一旦涉及修改(UPDATEDELETE)或显式加锁读,InnoDB 仍必须获取 X 锁或 S 锁来保证隔离性。

  • 关键区别SELECT * FROM user WHERE id=123 → 走 MVCC,无锁SELECT * FROM user WHERE id=123 FOR UPDATE → 必须加 X 锁,哪怕数据没变
  • 容易踩的坑:误以为“开了 MVCC 就不会锁表”,结果在高并发更新场景下,因索引缺失或临键锁范围过大,导致大量事务排队等待,监控看到 innodb_row_lock_waits 持续上涨
  • 验证方式:可通过 SELECT * FROM information_schema.INNODB_TRX 查看当前活跃事务及其锁等待状态,结合 INNODB_LOCKSINNODB_LOCK_WAITS 定位具体阻塞链

索引和锁的关系不是“有索引就安全”,而是“索引质量直接决定锁的粒度和范围”。一个没走索引的 UPDATE 可能锁全表,而一个设计不当的联合索引(比如把低区分度字段放最左)会让临键锁覆盖大片无关数据——这些细节,在压测和慢日志分析里才真正暴露出来。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

664

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

246

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

281

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

514

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

253

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

386

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

529

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

599

2023.08.14

PS使用蒙版相关教程
PS使用蒙版相关教程

本专题整合了ps使用蒙版相关教程,阅读专题下面的文章了解更多详细内容。

52

2026.01.19

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.8万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 801人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号