MySQL锁总结

锁分类

在MySQL中,

按锁粒度分类:全局锁、表级锁和行级锁。

按锁级别分类:共享锁(读锁)、排他锁(写锁)和意向锁。

说明:

意向锁是 InnoDB 自动加的,不需要用户干预。

对于INSERT、UPDATE和DELETE,InnoDB 会自动给涉及的数据加排他锁;

对于一般的SELECT语句,InnoDB 不会加任何锁,事务可以通过以下语句显式加共享锁或排他锁。

共享锁:SELECT … LOCK IN SHARE MODE;

排他锁:SELECT … FOR UPDATE;

全局锁

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

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

image-20230415192348573

对数据库进行进行逻辑备份之前,先对整个数据库加上全局锁,一旦加了全局锁之后,其他的DDL、DML全部都处于阻塞状态,但是可以执行DQL语句,也就是处于只读状态,而数据备份就是查询操作。 那么数据在进行逻辑备份的过程中,数据库中的数据就是不会发生变化的,这样就保证了数据的一致性和完整性。

语法

加全局锁

1
flush tables with read lock ; 

释放全局锁

1
unlock tables ; 

表级锁

表级锁,每次操作锁住整张表。对于表级锁,主要分为以下三类: 表锁、元数据锁(meta data lock,MDL)、 意向锁

表锁

分为两类:表读锁和表写锁

  • 语法

加锁:lock tables 表名… read/write。

释放锁:unlock tables / 客户端断开连接 。

  • 特点

image-20230415192406198

  • 结论:

读锁不会阻塞其他客户端的读,但是会阻塞写。写锁既会阻塞其他客户端的读,又会阻塞其他客户端的写。

元数据锁

meta data lock , 元数据锁,简写MDL。

MDL加锁过程是系统自动控制,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要作用是维护表元数据的数据一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性****。

image-20230415192420954

总结:执行了select、update、delete、insert操作后就不能再次执行alter table,反之亦然。避免了DML与DDL冲突。

意向锁

为了避免DML在执行时,加的行锁与表锁的冲突,在InnoDB中引入了意向锁,使得表锁不用检查每行数据是否加锁,使用意向锁来减少表锁的检查。

意向锁和行锁一起出现,当一条记录加了行锁后,它也会加上意向锁。

分类

意向共享锁(IS): 由语句select … lock in share mode添加 。 与表锁共享锁(read)兼容,与表锁排他锁(write)互斥。 就是说其中有一条记录加上了IS锁,就不能加表写锁了。

意向排他锁(IX): 由insert、update、delete、select…for update添加 。与表锁共享锁(read)及排他锁(write)都互斥,意向锁之间不会互斥。

一旦事务提交了,意向共享锁、意向排他锁,都会自动释放。

行级锁

行级锁,每次操作锁住对应的行数据。只应用于InnoDB引擎,分为以下三类:

image-20230415192433482

注意:默认情况下,InnoDB工作在可重复读隔离级别下,并且会以Next-Key Lock的方式对数据行进行加锁,这样可以有效防止幻读的发生。Next-Key Lock是行锁和间隙锁的组合,当InnoDB扫描索引记录的时候,会首先对索引记录加上行锁(Record Lock),再对索引记录两边的间隙加上间隙锁(Gap Lock)。加上间隙锁之后,其他事务就不能在这个间隙修改或者插入记录。

行锁

分为了共享锁和排他锁

对应SQL语句

image-20230415192505882

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

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

间隙锁和临键锁

对于它们的特点,具体见这篇文章:行级锁介绍

总结

  • 记录锁、间隙锁、临键锁,都属于排它锁;
  • 记录锁就是锁住一行记录;
  • 间隙锁只有在事务隔离级别 RR 中才会产生;
  • 唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁;
  • 普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;
  • 间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现 幻读 现象;
  • 普通索引的间隙,优先以普通索引排序,然后再根据主键索引排序;
  • 事务级别是RC(读已提交)级别的话,间隙锁将会失效
  • 间隙锁唯一目的是防止其他事务插入间隙。间隙锁可以共存,一个事务采用的间隙锁不会阻止另一个事务在同一间隙上采用间隙锁。

MySQL锁总结
http://example.com/2023/04/15/MySQL锁总结/
作者
程序员小魏
发布于
2023年4月15日
许可协议