MySQL锁机制
MySQL中锁主要分为以下几种:
- 全局锁
- 表级锁
- 表锁
- 元数据锁
- 意向锁
- 行级锁
- 行锁
- 间隙锁
- 临建锁
–
首先需要了解共享锁和排他锁
共享锁和排他锁
在 MySQL 中锁可以分为两大类,分别是shared (S)locks和 exclusive (X) locks。
- S锁,称为共享锁(也被称为读锁),事务在读取记录的时候获取S锁,它允许多个事务同时获取S锁,互相之间不会冲突。
- X锁,称为独占锁(排他锁,也被称为写锁),事务在修改记录的时候获取X锁,且只允许一个事务获取X锁,其它事务需要阻塞等待
S 锁之间不冲突,X锁则为独占锁,所以 X之间会冲突,X和S也会冲突。
–
全局锁(可以读不能写)
全库数据备份时需要用到全局锁(锁的范围-整个数据库)
# 开启全局锁
flush tables with read lock;
# 使用mysqldump进行数据备份 控制台命令
mysqldump -uroot -p123456 数据库名 > 数据库文件名.sql
# 释放全局锁
unlock tables;
–
由于全局锁性能较差,如何想数据备份不加全局锁,也可以使用如下命令
# 在InnoDB我们可以在备份时加上参数 --single-transaction 参数来完成不加锁的一致性数据备份 (基于快照实现)
mysqldump --single-transaction -uroot -p123456 数据库名 > 数据库文件名.sql
–
表级锁
表级锁分为:表锁、元数据锁、意向锁
表锁
表锁的范围 - 整张表
读锁read (所有客户端都可以读,不可以写)
写锁write (加锁所在的客户端及可以读,也可以写;其他客户端所有操作都无法进行)
# 加锁
lock tables 表名 read/write;
# 释放锁 (客户端关闭自动释放锁)
unlock tables;
–
元数据锁
元数据锁(meta data lock,MDL),元数据锁也分为读锁和写锁:
MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。
MDL锁主要作用是维护元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性。
在MySQL5.5中引入了MDL,为了避免DML与DDL冲突
- 当 对一张表进行增删改查(DML) 的时候,加MDL读锁(共享),阻止其他事务对表结构的修改
- 当 对表结构进行变更(DDL) 操作的时候,加MDL写锁(排他),阻止其他事务对表的操作
维护元数据的数据一致性
确保在执行 DDL操作(如 CREATE TABLE、DROP TABLE、ALTER TABLE)时,元数据不会被其他事务同时修改。
下面SQL语句所加的元数据锁
–
意向锁
为了避免DML在执行时,加的行锁与表锁的冲突,在InnoDB中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减
少表锁的检查,只需要判断表锁和意向锁是否兼容
- 意向共享锁(IS):与表锁共享锁(read)兼容,与表锁排它锁(write)互斥,
- 意向排他锁(IX):与表锁共享锁(read)及排它锁(write)都互斥。意向锁之间不会互斥。
意向锁是一种 MySQL 数据库中的锁,用于表级锁协调多个行级锁的使用。在表级锁定一个表之前,MSQL 需要先获得一个意向锁,以表明要获取的锁类型(读锁或写锁),避免其他事务锁定整个表或锁定一部分表时引发死锁。
意向锁是一种轻量级锁,它不会影响其他事务的读操作,只有在某个事务要对表进行写操作时才会加上意向锁,而其他事务在读取表时只需要获取读锁,不需要等待意向锁的释放。
意向锁可以提高数据库并发性能,防止死锁的发生。它是表级锁,而不是行级锁。
查看意向锁及行锁的加锁情况:
select object_schema,object_name,index_name,lock_type, lock_mode,lock_data from performance_schema.data_locks;
–
行级锁
行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。
InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。
对于行级锁,主要分为以下三类:
- 行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持
- 间隙锁(Gaplock):锁定索引记录间隙(不含该记录),确保率引记录间不变,防止其他事务在这个间隙进行insert,产生幻读,在RR隔离级别下都支持(开区间锁住两个索引间的间隙)
- 临键锁(Next-KeyLock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持。(可以理解为左开右闭的区间,包含的前面的间隙和右边索引所在的数据)
–
行锁
行锁也分为读锁和写锁
- 针对唯一(主键)索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁。(行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁)
- InnoDB的行锁是针对于索引加的锁,不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,此时就会升级为表锁
间隙锁和临建锁
默认情况下,InnoDB在 REPEATABLE READ(RR)事务隔离级别运行,InnoDB使用 next-key锁进行搜索和索引扫描,以防止幻读。
- 索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。
- 索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-keylock退化为间隙锁。(因为已经遍历到最后一个了,而且不满足,所以不需要加行锁了,临建锁退化成间隙锁)
- 索引上的范围查询(唯一索引)–会访问到不满足条件的第一个值为止