mysql之锁

在任何语言中,当进程中或者线程中存在并发访问同一个资源时,为了保证数据一致性,必须对共享资源添加相应的锁。mysql亦是如此。mysql属于磁盘中的共享资源,任何客户端都可以去相应DML和DDL操作。所以锁对于mysql而言至关重要。

mysql中锁,按照粒度划分,可以分为以下三类:

全局锁:锁定数据库中所有的表。

表级锁: 每次操作都锁住整张表。

行级锁:每次操作锁住对应的行数据。

1、全局锁

全局锁就是对整个数据库加锁,加锁之后,整个实例就处于只读状态。一般使用场景是数据库备份。为什么要备份的时候加锁呢? 这是因为当备份的时候,假设不加锁,那备份的时候,正好遇到多条数据更新,其中一条更新完成后,此时备份完成。那备份中的数据是不包含后面几条更新的数据的,这会导致数据库的数据是混乱的。

备份的操作流程:

1、flush tables with read lock ; #加锁

2、mysqldump -uroot -p1q2w3e database > a.sql #备份数据

3、unlock table; #释放锁

2、表级锁

2.1 表锁

(1)读锁

lock tables tb_user read;

mysql之锁_第1张图片

当使用读锁时,不会阻塞读操作,但是会阻塞写操作。

(2)写锁

ock tables tb_user write;

mysql之锁_第2张图片  当使用写锁时,即会阻塞读操作,又会阻塞写操作。

2.2 元数据锁

此锁是系统自动控制的,主要是为了避免DML和DDL冲突,保证读写的一致性。

以下图中左侧是DML的sql更新语句,右侧是DDL的更新语句,左侧在执行的过程中,右侧的对表增加字段的语句则会阻塞。

mysql之锁_第3张图片

 当DML更新语句执行过程中,对元数据锁进行相应查询,可以获取到相应的锁类型。

mysql之锁_第4张图片

 lock_type的类型:

1、SHARED_READ_ONLY / SHARED_NO_READ_WRITE:  对应的是表锁,lock tables read/write

2、SHARED_READ : 对应是select 、select ....lock in share mode  与SHARED_READ、 SHARED_WRITE兼容,与 EXCLUSIVE互斥

3、 SHARED_READ:对应的 insert update delete  select ....lock for update 与SHARED_READ、 SHARED_WRITE兼容,与 EXCLUSIVE互斥

4、EXCLUSIVE :对应的是alter table 与其他的MDL都互斥

2.3  意向锁

为了解决DML行锁和表锁的冲突问题。当A客户端对表进行DML操作时,此时B客户端想对表增加表锁。在增加表锁时需要判断此表中是否存在行锁,如果没有意向锁的前提下,则会对此表一行一行检测。效率低。为了解决此问题,引入意向锁,当A客户端对表进行DML操作时,会对整张表增加一个意向锁,B客户端增加表锁时直接通过意向锁来判断,大大增加了效率。

mysql之锁_第5张图片

 从图中可以看到,当对表进行更新操作时,右侧对表加锁时,直接阻塞。

意向锁的类型:

意向锁读锁IS:是表中select  select ...lock in share mode ,与表读锁兼容 与写锁互斥

意向锁写锁IX:  是表中的 update delete insert操作,与表读锁兼容  与写锁互斥 

3、行锁

行锁,是锁在行数据中,锁定粒度是最小的,发生锁的概率最低,并发度最高。

在InnoDB引擎中,一般是基于索引中索引项加锁实现的,而不是对记录进行加锁。行级锁分为3类:

1、行锁

2、间隙锁

3、临间锁

 3.1 行锁

当然行锁分为读锁和写锁。

读锁(共享锁):是select ...in share mode 。与写锁互斥 但与读锁兼容

写锁(排他锁):是update delete insert 。与读锁和写锁都互斥

mysql之锁_第6张图片

 注意:

1、上图1中对id为1的进行更新操作,右侧中查询时I写锁,然后对此行添加读锁,会被阻塞,但是如果对id=2的添加锁则会成功,行锁只会对相同数据集进行加锁。

2、图2中对name为aa的进行更新,右侧对name为cat的添加读锁,按理说应该可以成功的,但是右侧加锁阻塞了,这是因为name没有添加索引,在没有索引的情况下,行级锁会上升为表锁。

3.2 间隙锁

我们知道行级锁一般都是对索引加锁,而索引和索引之间空白处,是否需要添加锁呢,以下图中当左侧对id为5的数据进行更新时(id为5的数据是不存在的),此时右侧查询可知,对lock_data为8的数据加了GAP锁,此锁为间隙锁,含义表示对8之前的空白数据进行加锁。此时右侧做8之前数据的insert操作都是阻塞的。这样做的目的是什么?

假如不添加间隙锁,右侧添加成功,对于同一数据,左侧的数据更新成功,左侧和右侧用户都会出现幻读现象,因为左侧更新的时候数据是不存在的,更新之后出现此数据了,右侧用户插入之后发现数据被更新了,出现幻读。所以间隙锁的目的是保证数据一致性,避免出现幻读现象

mysql之锁_第7张图片 3.3 临键锁

指在索引上的某个键上设置的锁。它会锁住指定键值的记录,以及在键值之前的间隙,以下图中左侧对>=11的范围加了读锁,右侧查询的时候,对11增加一个临键锁,右表中有3个范围11-19 19-25 25以上正无穷,当添加此锁之后,不允许其他事务对此范围做增删操作,保证了数据的一致性。

mysql之锁_第8张图片

 总结:

1、全局锁主要用于备份整个数据库

2、表锁用于备份整张表,元数据锁主要用于解决DML和DDL之间的冲突,意向锁主要用于解决加表锁时需要判断是否存在行锁的,此时查询效率问题。

3、行锁主要用于解决数据之间的并发操作,对于同一个数据需要保证其原子性。间隙锁主要用于索引之间空白数据的插入和查询数据一致性问题。临键锁主要用于一个键值和在该键值前后的间隙,保证此范围的插入和查询数据一致性问题。

你可能感兴趣的:(mysql,mysql,数据库)