【搞定面试之mysql】第三篇 mysql的锁

目录

​编辑

前言:

全局锁

表级锁

表锁

元数据锁

意向锁

行级锁

总结


前言:

锁这个词语大家都不陌生吧,在并发的情况下,它可谓是神通广大,没有它那我们对于许多软件,网站的使用体验就会大打折扣,今天我们一起学习mysql的锁,来探究大名鼎鼎的mysql数据库是如何保证并发安全的。

全局锁

介绍

全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。

其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。

● 特点

数据库中加全局锁,是一个比较重的操作,存在以下问题:

1.如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。

2.如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。

在InnoDB引擎中,我们可以在备份时加上参数-single-transaction参数来完成不加锁的一致性数据备份。

表级锁

介绍

表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB等存储引擎中。

对于表级锁,主要分为以下三类:
1.表锁
2.元数据锁
3. 意向锁

表锁

一句话:读锁大家都只能读,写锁就只有本客户端能写能读。

元数据锁

元数据锁 是 MySQL 用来保护表结构 的一种表级锁 。它的核心作用就一句话:防止在事务执行过程中,表结构被其他线程修改

如果没有 MDL,可能会出现这种灾难:一个事务正在查询某张表,另一个事务同时执行 ALTER TABLE 把字段删了,导致查询线程读到错误的数据结构,甚至崩溃。

  • 读锁:当有事务对表进行 DML(增删改查)时,会自动获得 MDL 读锁。多个事务可以同时持有读锁。

  • 写锁:当执行 DDL (如 ALTER TABLEDROP TABLE)时,需要 MDL 写锁。写锁与任何读锁都不兼容,所以必须等待所有持有读锁的事务结束后才能执行。

加锁时机 :MySQL 在事务开始访问表 时加 MDL,在事务提交或回滚时释放。

意向锁

意向锁是表级锁,由InnoDB自动维护,分为意向共享锁(IS)和意向排他锁(IX)。

作用 :当另一个事务想加表锁时,不需要遍历每一行检查是否有行锁,直接看意向锁就知道------快速判断表里是否有行锁,提高锁冲突检测效率。

  • 有了 意向共享锁(IS) → 可以再加 表级共享锁(S) ,但不能加 表级排他锁(X)

  • 有了 意向排他锁(IX)不能加任何表锁(S 或 X 都不行)。

比如事务 A 持有 IX 锁,事务 B 执行 LOCK TABLES t READ就会失败因为这样加了表级共享锁(S)

  • 意向锁之间互相兼容,不影响其他事务加意向锁。

可以简单的理解

共享锁:就是读锁的意思,然后都只能读

排他锁:就是写锁的意思,然后自己能读能写,别人啥都干不了

行级锁

介绍

行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。

假设有一个 id 索引,已有的数据是:1, 5, 10

  • 行锁 :锁住某一行,比如 id=5

  • 间隙锁 :锁住记录之间的空隙,比如 (1,5) 表示大于1且小于5的范围,不包含1和5

临键锁 = 记录锁 + 间隙锁,它锁的是一个"左开右闭"的区间。

比如临键锁 (1,5] 的含义是:锁住 大于1 且 小于等于5 的范围。

  • 左边是"开",不包含1。

  • 右边是"闭",包含5。

所以当事务对 id=5 这条记录加临键锁时,实际锁住的是 (1,5] 这个区间,即:

  • 禁止其他事务插入 id 在 (1,5) 之间的值(如2,3,4)

  • 同时禁止其他事务修改或删除 id=5 这行

临键锁的设计初衷是 防止幻读锁定当前记录

共享锁:只能读这行 不能修改这行,获取排他锁也就是进行写操作。

排他锁:其他事务啥都不能干。

行锁类型为排他锁:表示在进行这些操作时,其他事务啥都不能干

为共享锁:其他事务可以读

默认情况下,InnoDB在REPEATABLE READ事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。

1.针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁。

就是当你用唯一索引比如id=5,肯定就只能查到id=5的数据,**临键锁是行锁+间隙锁,因为只有一条所以不可能发生幻读,所以就不用间隙锁,**将会自动优化为行锁。前提是能查到。

2.InnoDB的行锁是针对于索引加的锁不通过索引条件检索数据或者索引失效,那么InnoDB将对表中的所有记录加锁,此时就会行锁升级为表锁

我来解释一下

1:

比如表里 id 有 1、5、10,你执行
SELECT * FROM t WHERE id = 8 FOR UPDATE(8 不存在)。

  • 不会锁任何一行,而是锁住 5 和 10 之间的间隙 (5,10)

  • 作用:禁止别人插入 8,防止幻读。

2:比如普通索引 age,有 1、2、2、5。你执行
SELECT * FROM t WHERE age = 2 FOR UPDATE

  • 会锁住所有 age=2 的行,同时锁住 age=2 到下一个值(5)之间的间隙。

  • 因为普通索引不唯一,必须防止别人插入另一个 age=2,所以间隙要锁到下一个不同的值为止。

3:

比如主键 id,你执行
SELECT * FROM t WHERE id > 5 FOR UPDATE

  • 会锁住 id 从 6 开始的所有行,并且一直锁到最大值。

  • 如果中途遇到一个不满足条件的值(比如 id=10 是最大值,再往后没有),就只锁到最大值。

  • 但如果是 id >= 5,就会锁住 5 以及后面的所有行,直到最后。

总结

在进行学习的时候一定要构建知识网络,索引,锁,mvcc,事务他们都是有关联的,因为事务隔离性所以来了锁和mvcc,索引也会影响锁,比如没索引行锁变表锁,都是有关联的,内容确实多,但是把他们联系起来然后多看几遍我相信你的收获一定不小。

相关推荐
Chenyiax1 分钟前
从一次请求看懂 OkHttp:架构、调度与连接管理
后端
爱勇宝1 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
AskHarries1 小时前
工具失败时怎么办:重试、回滚、人工确认和风险提示
后端·程序员
苏三说技术3 小时前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎4 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode4 小时前
Redis 在生产项目的使用
前端·后端
用户559822481224 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode4 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战4 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha4 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端