目录
前言:
锁这个词语大家都不陌生吧,在并发的情况下,它可谓是神通广大,没有它那我们对于许多软件,网站的使用体验就会大打折扣,今天我们一起学习mysql的锁,来探究大名鼎鼎的mysql数据库是如何保证并发安全的。
全局锁
介绍
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DML的写语句,DDL语句,已经更新操作的事务提交语句都将被阻塞。
其典型的使用场景是做全库的逻辑备份,对所有的表进行锁定,从而获取一致性视图,保证数据的完整性。
● 特点
数据库中加全局锁,是一个比较重的操作,存在以下问题:
1.如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆。
2.如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。
在InnoDB引擎中,我们可以在备份时加上参数-single-transaction参数来完成不加锁的一致性数据备份。
表级锁
介绍
表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB等存储引擎中。
对于表级锁,主要分为以下三类:
1.表锁
2.元数据锁
3. 意向锁
表锁

一句话:读锁大家都只能读,写锁就只有本客户端能写能读。
元数据锁
元数据锁 是 MySQL 用来保护表结构 的一种表级锁 。它的核心作用就一句话:防止在事务执行过程中,表结构被其他线程修改。
如果没有 MDL,可能会出现这种灾难:一个事务正在查询某张表,另一个事务同时执行 ALTER TABLE 把字段删了,导致查询线程读到错误的数据结构,甚至崩溃。
读锁:当有事务对表进行 DML(增删改查)时,会自动获得 MDL 读锁。多个事务可以同时持有读锁。
写锁:当执行 DDL (如
ALTER TABLE、DROP 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,索引也会影响锁,比如没索引行锁变表锁,都是有关联的,内容确实多,但是把他们联系起来然后多看几遍我相信你的收获一定不小。
