MySQL 锁机制全解析从锁的分类到并发更新是否阻塞(最新推荐)

 更新时间:2025年12月31日 09:26:46   作者:蜂蜜黄油呀土豆  
本文介绍了MySQL的锁机制,包括全局锁、表锁和行锁,并详细分析了这些锁在并发场景下的表现和影响,感兴趣的朋友跟随小编一起看看吧

引言

在并发场景下,数据库需要解决三类核心问题:

  • 数据一致性:不能读到脏数据
  • 并发安全:多个事务同时修改数据时不出错
  • 性能权衡:在一致性和并发性能之间取得平衡

MySQL(准确来说是 InnoDB 存储引擎)通过一整套多层次锁机制来解决这些问题。这些锁并不是“随便加的”,而是紧密围绕 事务隔离级别、索引结构、并发访问模式 设计出来的。

本文将从三个层次展开:

  • MySQL 有哪些锁?
  • 表锁和行锁到底解决了什么问题?
  • 真实并发场景下,SQL 会不会阻塞?为什么?

一、MySQL 有哪些锁?——三大类锁体系

作用范围来看,MySQL 的锁可以分为三大类:

全局锁 → 表级锁 → 行级锁

全局锁(Global Lock)

1.1 什么是全局锁?

全局锁会锁住整个数据库实例,使其进入只读状态。

最典型的加锁方式是:

FLUSH TABLES WITH READ LOCK;

此时:

  • 所有表都只能读
  • 所有写操作(INSERT / UPDATE / DELETE)都会被阻塞
1.2 全局锁的典型使用场景

逻辑备份

mysqldump --single-transaction ...

在早期 MySQL 版本中,为了保证备份过程中数据一致,通常需要加全局读锁。

1.3 全局锁的问题
  • 整库不可写
  • 在线业务几乎不可接受

现在更多使用 MVCC + 一致性快照,避免全局锁

表级锁(Table-level Lock)

表级锁的作用范围是 单张表,开销小,但并发能力有限。

2.1 表锁(Table Lock)

LOCK TABLE t_order READ;
LOCK TABLE t_order WRITE;
  • READ:其他线程可读,不可写
  • WRITE:其他线程既不可读,也不可写

InnoDB 一般不推荐使用显式表锁

2.2 元数据锁(MDL,Metadata Lock)

MDL 是自动加的锁,很多人“被它坑过,但不知道是它”。

  • 对表进行 CRUD → 加 MDL 读锁
  • 对表进行 DDL(ALTER / DROP) → 加 MDL 写锁

读写互斥!

-- 事务 A
SELECT * FROM t_order; -- 持有 MDL 读锁
-- 事务 B
ALTER TABLE t_order ADD COLUMN xxx; -- 等待

线上 DDL 阻塞业务的元凶

2.3 意向锁(Intention Lock)

意向锁是 InnoDB 行锁的“前置声明”,存在于表级别。

  • 意向共享锁(IS)
  • 意向排他锁(IX)

作用:让表锁与行锁能快速判断是否冲突

“我要锁某几行了,你别直接给我整个表上锁”

行级锁(Row-level Lock)

行锁是 InnoDB 的核心竞争力,并发性能的关键。

3.1 记录锁(Record Lock)

锁住 某一条索引记录

  • S 锁(共享锁):读
  • X 锁(排他锁):写
SELECT * FROM t_order WHERE id = 10 LOCK IN SHARE MODE;
UPDATE t_order SET status = 1 WHERE id = 10;
3.2 间隙锁(Gap Lock)

锁住的是 索引区间之间的“空隙”

  • 只存在于 RR(可重复读)隔离级别
  • 目的:防止幻读
SELECT * FROM t_order WHERE id BETWEEN 10 AND 20 FOR UPDATE;

锁住 (10, 20) 这个区间,阻止插入新记录

间隙锁之间是兼容的

3.3 临键锁(Next-Key Lock)

Next-Key Lock = Record Lock + Gap Lock

  • 锁住记录本身
  • 同时锁住前面的间隙

这是 InnoDB RR 隔离级别的默认加锁策略

二、表锁和行锁解决了什么问题?

锁类型解决的问题
表锁DDL 与 DML 冲突
行锁并发更新同一行
间隙锁防止幻读
临键锁范围查询 + 插入一致性

本质目标只有一个:
在并发环境下,保证事务隔离语义成立

三、并发场景实战分析:到底会不会阻塞?

场景 1:两个事务同时 UPDATE 同一条记录

UPDATE t_order SET status = 1 WHERE id = 100;

会阻塞

  • 第一个事务获取 id=100 的 X 锁
  • 第二个事务只能等待

场景 2:更新不同主键的记录

-- 事务 A
UPDATE t_order SET status = 1 WHERE id = 100;
-- 事务 B
UPDATE t_order SET status = 1 WHERE id = 200;

不会阻塞

  • 行锁粒度是“记录级”
  • 主键索引精确定位

场景 3:更新主键范围(存在索引)

UPDATE t_order SET status = 1 WHERE id BETWEEN 100 AND 200;
  • 加的是 Next-Key Lock
  • 会锁住区间

其他事务在该区间 INSERT 会被阻塞

场景 4:WHERE 条件未命中索引

UPDATE t_order SET status = 1 WHERE order_no = 'xxx';

如果 order_no 没有索引

  • InnoDB 会 全表扫描
  • 锁升级为 锁住大量记录甚至整表

这才是线上“莫名其妙阻塞”的根源

总结

锁不是 SQL 层决定的,而是:

SQL + 索引 + 隔离级别 + 引擎共同作用的结果

关键记忆点

  • RR 隔离级别 ≠ 只有行锁
  • Next-Key Lock 是默认策略
  • 无索引 ≈ 放弃行锁优势
  • MDL 是 DDL 阻塞的幕后黑手

实战建议

  • 所有更新 SQL 必须走索引
  • 范围更新要评估间隙锁影响
  • 线上 DDL 使用 Online DDL
  • 用 show engine innodb status 排查锁等待

到此这篇关于MySQL 锁机制全解析:从锁的分类到并发更新是否阻塞的文章就介绍到这了,更多相关mysql 锁机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL事务隔离级别和一致性详解

    MySQL事务隔离级别和一致性详解

    文章讲解了数据库事务的隔离性及四个级别(读未提交、读提交、可重复读、串行化),不同级别解决不同并发问题,强调一致性需用户与数据库共同保障
    2025-08-08
  • linux mysql忘记密码的多种解决或Access denied for user ''root''@''localhost''

    linux mysql忘记密码的多种解决或Access denied for user ''root''@''local

    linux mysql忘记密码的多种解决方法。
    2009-07-07
  • mysql索引(覆盖索引,联合索引,索引下推)

    mysql索引(覆盖索引,联合索引,索引下推)

    这篇文章主要介绍了mysql索引(覆盖索引,联合索引,索引下推),文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • mysql中怎样使用合适的字段和字段长度

    mysql中怎样使用合适的字段和字段长度

    这篇文章主要介绍了mysql中怎样使用合适的字段和字段长度问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • SQL语句单引号与双引号的使用方法

    SQL语句单引号与双引号的使用方法

    这篇文章主要介绍了SQL语句中单引号、双引号的使用方法,分别讲述,虽然说的是Insert语句, 但是Select、Update、Delete语句都是一样的,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-03-03
  • mysql中url时区的陷阱该如何规避详解

    mysql中url时区的陷阱该如何规避详解

    最近在工作中发现一个问题,是关于mysql中url时区的,发现这个陷阱如果大家不注意可能都会遇到,所以给大家总结下,这篇文章主要给大家介绍了关于mysql中url时区的陷阱该如何规避的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-08-08
  • mysql 8.0.27 解压版安装配置方法图文教程

    mysql 8.0.27 解压版安装配置方法图文教程

    这篇文章主要为大家详细介绍了mysql 8.0.27 解压版安装配置方法图文教程,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • MySQL找出未提交事务信息的方法分享

    MySQL找出未提交事务信息的方法分享

    这篇文章主要给大家介绍了关于MySQL如何找出未提交事务信息的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用MySQL具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-06-06
  • MySQL实际项目中常用的 DDL 模板

    MySQL实际项目中常用的 DDL 模板

    本文详细介绍了数据库表的常见操作,包括创建带审计字段和索引的模板、修改表结构(如新增、删除、修改字段)、索引管理(新增、删除普通、唯一索引及联合索引)、外键约束的新增和删除、表结构变更(如重命名表、设置字符集)以及删除表,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • MySql报错:unblock with mysqladmin flush-hosts的解决方案

    MySql报错:unblock with mysqladmin flush-hosts的解

    这篇文章主要介绍了MySql报错:unblock with mysqladmin flush-hosts的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2026-03-03

最新评论