锁介绍#
MySQL 中的锁,按照锁的粒度分为以下三类:
- 全局锁:锁定数据库中的所有表
- 表级锁:每次操作锁住整张表
- 行级锁:每次操作锁住对应的行数据
全局锁#
全局锁就是对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续 DML 的写语句,DDL 语句,已经更新操作的事务提交语句都将被阻塞
典型场景是锁定所有表进行全库备份,如果不加锁,就如下图,可能出现产生了订单但是库存没有扣减的数据不一致
如果加锁,只能读不能写,保证了备份的时刻全局一致
flush tables with read lock; # 加锁
mysqldump -uroot -p123456 database > database.sql # 备份
unlock tables; # 解锁
加全局锁是一个比较重的操作,存在下列弊端
- 如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆
- 如果在从库上备份,那么在备份期间从库不能执行主库同步过来的二进制日志 binlog,会导致主从延迟
在 InnoDB 引擎中,加上参数 --single-transaction
可以实现 不加锁 的一致性数据备份 ,其底层使用的是快照读进行备份操作
mysqldump --single-transaction -uroot -p123456 database > database.sql
表级锁#
表级锁,每次操作锁住整张表,锁定粒度大,发生锁冲突的概率最高,并发度最低,应用在 MyISAM、InnoDB、BDB 等存储引擎中
对于表级锁,主要分为以下三类:
- 表锁
- 元数据锁 meta data lock MDL
- 意向锁
表锁#
对于表锁,分为两类:
- 表共享读锁 read lock
- 表独占写锁 write lock
共享读锁 read lock,都可以读,但是都不能写
独占写锁 write lock,只能上锁方读写,其余方无法操作
元数据锁#
meta data lock MDL 加锁过程由程序自动控制,无需显式使用,在访问一张表的时候会自动加上,MDL 锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作;为了避免 DML 与 DDL 冲突,保证读写的正确性
在 MySQL v5.5 中引入了 MDL:
当对一张表进行增删改查 DML 的时候,加 MDL 读锁 共享
当对表结构进行变更操作 DDL 的时候,加 MDL 写锁 排他
元数据锁大意,事物进行当中,无法修改表结构;
事物进行时的 DML 会申请 MDL 共享读锁 SHARE_READ/SHARE_WRITE
修改表结构的 DDL 会申请 MDL 排他锁 EXCLUSIVE
MDL 主要是针对表结构的 meta data,保证读取表结构的共享读锁 SHARE 和变更表结构的排他写锁 EXCLUSIVE,能够限制增删改查 DML 时表结构的一致
意向锁#
为了避免 DML 在执行时,加的行锁与表锁的冲突,在 InnoDB 中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查
当表中其他事务持有意向共享锁 IS,此时想给表加 read 表锁可以,但加 write 表锁不行,需要等事务释放意向共享锁
当表中其他事务持有意向排他锁 IX,此时想给表加 read 表锁和 write 表锁都不行,需要等事务释放意向排他锁
行级锁#
行级锁,每次操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最低,并发度最高,应用在 InnoDB 存储引擎中
行锁 Record Lock:锁定单个行记录的锁,防止其他事务对此行进行 update 和 delete,在 ReadCommit、RepeatableRead 隔离级别下都支持
间隙锁 Gap Lock:锁定索引记录间隙 不含该记录,确保索引记录间隙不变,防止其他事务在这个间隙进行 insert,产生幻读,在 RepeatableRead 隔离级别下都支持
临键锁 Next-Key Lock:行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙 Gap,在 RepeatableRead 隔离级别下支持
行锁 Record Lock#
两种行锁:
- 共享锁 S:允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁
- 排他锁 X:允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁
类似于 read/write
相关 SQL 行锁类型
默认情况下,InnoDB 在 RepeatableRead 事务隔离级别运行,InnoDB 使用临键锁 next-key lock 进行搜索和索引扫描,以防止幻读
- 针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁
- InnoDB 的行锁是针对于索引加的锁,不通过索引条件检索数据,那么 InnDB 将对表中的所有记录加锁,此时就会 升级为表锁
间隙锁 gap lock / 临键锁 next key lock#
间隙锁 gap lock 唯一目的是防止其他事务插入间隙,间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁
有点难理解,借用笔记看看
小结#
- 概述
在并发访问时,解决数据访问的一致性、有效性问题
全局锁、表级锁、行级锁 - 全局锁
对整个数据库实例加锁,加锁后整个实例就处于只读状态
性能较差,数据逻辑备份时使用 - 表级锁
操作锁住整张表,锁定粒度大,发生锁冲突的概率高
表锁、元数据锁、意向锁 - 行级锁
操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最低
行锁、间隙锁、临键锁
此文由 Mix Space 同步更新至 xLog
原始链接为 https://blog.0xling.cyou/posts/mysql/mysql-1