跳至正文
来两杯美式
返回

MySQL 知识系列(三):锁机制与并发控制

By 来两杯美式
发布于

锁的分类


├── 全局锁(FTWRL)
├── 表级锁
│    ├── 数据锁(lock tables)
│    └── 元数据锁(MDL)
└── 行级锁
     ├── 共享锁(S 锁 / 读锁)
     └── 排他锁(X 锁 / 写锁)
引擎默认锁粒度是否支持事务
MyISAM表级
InnoDB行级(+ 表级)

读锁 / 写锁的兼容性

全局锁:FTWRL

FLUSH TABLES WITH READ LOCK;

整个库进入只读状态,主要用于保证数据备份的一致性(一般在备库、从库使用)。

表级锁

数据锁(lock tables)

LOCK TABLES t_user READ;      -- 其它会话只能读,不能写
LOCK TABLES t_user WRITE;     -- 其它会话不能读也不能写
UNLOCK TABLES;

元数据锁(MDL,MetaData Lock)

元数据 = 表结构、字段、数据类型、索引等。

行级锁

共享锁(S 锁 / 读锁)

SELECT * FROM user WHERE id = 1 LOCK IN SHARE MODE;

排他锁(X 锁 / 写锁)

SELECT * FROM user WHERE id = 1 FOR UPDATE;

UPDATE / DELETE / INSERT 隐式加 X 锁。

MVCC 多版本并发控制

MVCC 版本链(每个数据行通过 undo log 形成历史快照链)

InnoDB 在每行数据后面保存了 3 个隐藏列:

事务通过 ReadView(活跃事务 ID 集合) 沿版本链找到第一个对自己可见的版本——这就是非锁定一致性读

当前读 vs 快照读

类型语句读取版本是否加锁
当前读SELECT ... LOCK IN SHARE MODE最新加 S 锁
当前读SELECT ... FOR UPDATE最新加 X 锁
当前读UPDATE / DELETE / INSERT最新加 X 锁
快照读普通 SELECT历史版本(MVCC)不加锁

间隙锁(Gap Lock)与幻读

幻读问题

RR 隔离级别下,同一事务两次执行 SELECT * FROM user WHERE age > 10,两次结果行数不同(中间被别的事务插入了 age=15 的数据)。

间隙锁的引入

示例表:

示例表(id=1,age=10; id=2,age=30)

辅助索引 age 形成的”区间”:

age 索引上的间隙((-∞,10) (10,30) (30,+∞))

InnoDB 把 age 索引划分为:

间隙锁锁的是区间本身,不允许其他事务在间隙内 INSERT。

Next-Key Lock

Next-Key Lock = 行锁(Record Lock)+ 间隙锁(Gap Lock)

-- 锁定间隙 (10, 20),不会命中已有数据
SELECT * FROM user WHERE age = 11;

特性:

  1. 唯一索引等值查询(完全命中)→ 只用行锁,忽略间隙锁
  2. 普通索引查询 → 必加间隙锁(因为取值可能重复)
  3. 范围查询扫描过的区间 → 全部加锁(包括间隙)
-- name 字段无索引的 UPDATE:扫描整个表,所有间隙都会被锁
UPDATE user SET age = 20 WHERE name = 'a';

⚠️ 死锁高发场景:用无索引字段做条件更新,所有间隙都会被锁,并发时极易死锁。生产中应保证更新条件走索引


下一篇深入 InnoDB 的”日志系统”:redo log(崩溃恢复)+ undo log(事务回滚/MVCC)+ binlog(主从复制)三者的关系与两阶段提交。


分享这篇文章:
通过邮件分享这篇文章✓ 链接已复制
所属专题
MySQL
第 3 / 9 篇
查看系列全部文章
  1. 01.MySQL 知识系列(一):整体架构与存储引擎
  2. 02.MySQL 知识系列(二):索引结构与查询原理
  3. 03.MySQL 知识系列(三):锁机制与并发控制
  4. 04.MySQL 知识系列(四):日志系统:redo log、undo log、binlog
  5. 05.MySQL 知识系列(五):隔离级别、Spring 事务与查询流程
  6. 06.MySQL 知识系列(六):SQL 注入、版本特性与容量评估
  7. 07.MySQL 知识系列(七):SQL 调优(一)—— EXPLAIN 执行计划
  8. 08.MySQL 知识系列(八):SQL 调优(二)—— 索引设计与调优工具
  9. 09.MySQL 知识系列(九):CASE 语句、乐观锁与悲观锁实战

上一篇
Redis 知识系列(一):数据结构与单机原理
下一篇
MySQL 知识系列(二):索引结构与查询原理