原视频地址:【程序员必看】MySQL各种锁详解:7分钟彻底搞懂MySQL的各种锁_哔哩哔哩_bilibili

img

首先要有大局观,比如你要锁东西是把整栋楼锁住还是只锁一个房间,或者干脆只锁一个抽屉呢,这就是锁的粒度,也就是锁的范围大小,在MYSQL中锁的粒度如下

MYSQL锁的粒度

img

  • 全局锁:锁住整个数据库(相当于给整个大楼给封了),一个命令下来整个库谁也别想写数据,
    • 作用:显而易见用于全库备份时使用,全库备份需要保证数据一动不动,这就是全局锁的作用了
  • 表锁:锁住整张表(相当于锁一个房间),像老一点的MyISAM引擎默认就是表锁。
    • 好处:简单直接,开销小
    • 坏处:只要有一个人在房间操作其他所有人都要在门口排队,即并发差
  • 行锁:锁住当行数据(相当于只锁一个抽屉),这也是目前InnoDB用的
    • 好处:并发高,你给你的数据我改我的数据只要不是同一行数据咱两就互不影响
    • 坏处:开销大(管一堆钥匙,要比只管大门钥匙要麻烦很多),可能死锁(你拿着我的钥匙我拿着你的钥匙两人就卡着不动了)

MYSQL锁的派别

img

  • 悲观锁:它认为只要我改数据肯定就有人给我抢,所以它在干活前就用select…for update语句来锁住把数据锁的死死的,谁也别想动
    • 场景:用在秒杀,抢库存这一类高并发的场景中(写多读少),并发写操作多,冲突概率极大必须先下手为强
  • 乐观锁:它是乐天派,认为改数据时没那么多人跟我抢,所以它不加锁,直接去操作数据,只在最后要提交的时候,用版本号或者时间戳来比对一下,看看我干活的这期间有没有人都过我的数据,如果有人改了,这次提交就失败
    • 场景:适合像改文章,改商品信息这一类读多写少的场景,因为它省去了加锁的开销,性能就会好很多

MYSQL中锁自带的两种基本类型

img

相当于在图书馆看书时

共享锁(S锁/读锁):它就等于大家一起看书,一本书可以被很多人同时看,只要大家不在上面写字就行,即读读共享,读写互斥,在mysql中可以用lock in share mode这个语句加的就是一个读锁

排他锁(X锁/写锁):当我要改书的时候必须要把这本书拿走,自己一个人改,在你改完还回来之前,别人既不能看也不能改,即写写互斥,读写互斥,在mysql中可以用for update这个语句加的就是一个读锁

MYSQL中意向锁(Intention Lock)

img

但它想成一个挂在表门口的通知牌,它的作用就是为了提高效率,如果事务A锁了表里面的某一行数据,这个时候事务B它想要给整个表加一个锁,那MYSQL咋办呢,难道一行一行去检查有没有行锁吗,那表里面如果有上千万行数据查到猴年马月去,这数据库直接就会被卡死,所以InnoDB就设计了这个通知牌,当事务A给某一行加锁的时候,InnoDB会自动在这个表的门口上面挂个牌子,上面写着里面有人正在操作请注意,这样当事务B想来锁整张表的时候抬头一看这张表的门口上有个牌子,立刻就知道里面有行锁,有冲突,自己得等着,效率一下就上来了,所以意向锁本身它是一个表级锁,但它不是用来锁数据的,而是用来打配合提高效率的,

有了意向锁这个帮手我们再来看看InnoDB真正在一线干活的几个核心武器

MYSQL中记录锁(Record Lock)

img

第一个记录锁,记录锁这就是最纯粹的行锁,指哪打哪,只锁定你查询命中的那一条记录,比如能用注解where id = 10去更新,那他就只锁ID等于10这一行,这是我们最希望看到的最理想的情况

但是如果查询条件不是唯一的呢,比如查age>18这样的范围,这时候面试必考的知识点就来了-幻读

为了解决幻读InnoDB就掏出来他的大杀器间隙锁&临键锁

MYSQL中的间隙锁&临键锁

img

间隙锁它不锁任何已经存在的数据,就是一个开区间,它只是锁住记录和记录之间的那个缝,比如说索引里面有10和20,那他就锁住10-20这一个区间,让你没法在这个缝隙里面插入新的数据,它就像给数据之间放了个结界,任何新的换的数据都不允许冒出来。

而临键锁呢,他就是记录锁+间隙锁,它不但锁住记录本身,还把这条记录前面的那个缝也锁住了,这才是InnoDB在可重复读隔离级别下默认使用的锁,它就像一张大网,把记录和它旁边的缝全给罩住,让幻读无处遁形

所以说为什么有了MVCC还需要锁来防止幻读呢

MVCC保证了你读的时候看不到幻影,而临键锁保证了在别人写的时候造不出幻影,一个防读,一个防写

详细的解释:


🌱 背景:MVCC 与 幻读

在 MySQL 的 可重复读(REPEATABLE READ) 隔离级别中,主要通过 MVCC(多版本并发控制) 来解决「脏读」和「不可重复读」问题。

  • MVCC 的核心思想 是:每个事务在开始时,会看到一个“快照”(Snapshot)——也就是数据库在那个时间点上的一致性视图。
  • 因此,当事务读取时,不管其他事务后来插入/修改了什么,它都不会看到新数据(这是 MVCC 的作用)。

但是:
MVCC 只能保证读到的内容一致,却不能防止别的事务在你读的同时插入新的记录。这就导致了“幻读”的问题。


🧩 幻读(Phantom Read)

假设事务 A 执行:

1
SELECT * FROM users WHERE age > 20;

此时事务 B 在事务 A 未提交期间执行:

1
INSERT INTO users(age) VALUES(25);

那么事务 A 再次执行相同的 SELECT 时,会发现多了一行——这就是“幻影行”,即幻读


🔒 那为什么 MVCC 不够?

MVCC 只解决了“读一致性”的问题,它的作用是:

“你在读时,看不到别人已经提交的新数据。”

但它不能阻止别人去插入新行。换句话说:

  • 你读时,看不到幻影(MVCC 起作用);
  • 但别人写时,可能造出幻影(MVCC 无法阻止)。

所以当你要防止别人“造幻影”时,必须依赖 锁(尤其是 Next-Key Lock 临键锁)


⚙️ 临键锁(Next-Key Lock)的作用

在 InnoDB 中,Next-Key Lock = 行锁 + 间隙锁
它不只锁住已有的行,还锁住这些行之间的间隙(gap),从而阻止别的事务往这些间隙插入新行。

举例:

如果表中有 age = 18, 25, 30 三行,
那么查询 age > 20 时,InnoDB 可能会锁住区间 (20, 30)
这使得别人无法在 20~30 之间插入新数据。


🧠 理解那句话:

“MVCC 保证了你读的时候看不到幻影,而临键锁保证了在别人写的时候造不出幻影,一个防读,一个防写。”

意思是:

  • MVCC:让你在读时看到的世界是稳定的,不会因为别的事务插入/修改而“看见幻影”;
  • 临键锁(Next-Key Lock):防止别人在你事务期间插入“幻影行”,即从“写的角度”避免幻读的出现。

换句话说:

  • MVCC 是 “读一致性” 的机制;
  • 锁是 “写互斥” 的机制;
    两者配合,才能在高并发下既读得快又能保证事务隔离性。

✅ 小结类比

机制 防止什么 方式 说明
MVCC 读到幻影(读时不一致) 读快照 “别人改了也不影响我现在看的”
临键锁 别人造幻影(写时插入) 锁定间隙 “别人不能在我查过的范围插入新行”

总结

img

总结;锁这个东西从来没有绝对的好与坏,全局锁虽然暴力,但是在备份的时候离不开它,行锁虽然精细,但你得承担死锁的风险,临键锁虽然能解决幻读,但它也可能锁住没有必要的范围,牺牲了一些性能