文章目录
- [一. MySQL中锁的作用](#一. MySQL中锁的作用)
- [二. MySQL中有哪些锁](#二. MySQL中有哪些锁)
- [三. 全局锁](#三. 全局锁)
-
- [3.1 介绍全局锁](#3.1 介绍全局锁)
- [3.2 全局锁语法](#3.2 全局锁语法)
- [3.3 全局锁特点](#3.3 全局锁特点)
- [3.4 不加锁备份](#3.4 不加锁备份)
- [四. 表级锁](#四. 表级锁)
-
- [4.1 表级锁介绍](#4.1 表级锁介绍)
- [4.2 表锁](#4.2 表锁)
- [4.3 元数据锁](#4.3 元数据锁)
-
- [4.4 意向锁](#4.4 意向锁)
- [五. 行锁](#五. 行锁)
-
- [5.1 行锁的分类](#5.1 行锁的分类)
- [5.2 行锁](#5.2 行锁)
- [5.3 间隙锁&临键锁](#5.3 间隙锁&临键锁)
一. MySQL中锁的作用
用来保护并发访问数据库资源的线程安全问题,防止多个进程同时操作数据库,导致数据库的错误操作。
二. MySQL中有哪些锁
- 全局锁:锁定数据库中所有表。
- 表级锁:每次操作锁住整张表。
- 行级锁:每次操作锁住对应的行数据。
三. 全局锁
3.1 介绍全局锁
定义:全局锁就是对整个数据库实列加锁,加锁后整个实列变成只读状态,已经更新操作的事务提交语句都将被阻塞。
使用场景:做全库的逻辑备份,对于所有的表进行锁定,从而获取一致性视图,保证数据的完整性。

如上操作不加锁的话,就可能会导致备份的数据库有问题,比如上面有新的订单了,但是库存没有减少,因此我们备份时,需要加上全局锁。
3.2 全局锁语法
- 全局锁加锁
sql
flush tables with read lock ;
- 数据备份
sql
mysqldump -uroot --p123456 itcast > itcast.sql
这个不是SQL语句,mysqldump是一个备份的工具,该指令需要在终端命令行中执行。
- 全局锁释放
sql
unlock tables ;
3.3 全局锁特点
- 如果在主库上备份,那么备份期间不能执行更新,业务基本上停摆。
- 如果在从库上备份,那么备份期间从库不能执行主库同步过来的二进制日志(binlog),会导致主从延迟。
3.4 不加锁备份
在innoDB引擎中,我们可以在备份时加上参数 --single-transaction 来完成不加锁的一致性数据备份。
sql
mysqldeump --single-transaction -uroot -p123456 itcast> itcast.sql
四. 表级锁
4.1 表级锁介绍
表级锁,每次操作锁住整张表。锁定粒度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB、BDB等存储引擎中。
表级锁有三类:
- 表锁
- 元数据锁
- 意向锁
4.2 表锁
表锁有两类:
- 表共享读锁:加锁后,该线程和其他线程可以读取表中数据,但都不能对表数据做写操作。

语法:
sql
lock tables 表名 read;
- 表独享写锁:加锁后,该线程可对表进行读和写,其他线程不能对该表进行操作,直到释放锁。

语法:
sql
lock tables 表名 write;
4.3 元数据锁
- 元数据锁,简称MDL。
MDL加锁是系统自动进行的,不需要显式调用。但对表进行增删改查时,会加上MDL锁。在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性。
这里的元数据可以理解为表的结构,也就是说当表涉及未提交事务时,是不能修改表的结构的。
在MySQL5.5中引入了MDL,对表进行增删改查SQL操作时,表会加上DML共享锁(共享);对表结构修改时,会加上DML排他锁(排他)。
- 常见的SQL操作时,所添加的元数据锁:
| 对应SQL | 锁类型 | 说明 |
|---|---|---|
| lock tables xxx read / write | SHARED_READ_ONLY / SHARED_NO_READ_WRITE | |
| select 、select ... lock in share mode | SHARED_READ | 与SHARED_READ、SHARED_WRITE兼容,与EXCLUSIVE互斥 |
| insert 、update、delete、select ... for update | SHARED_WRITE | 与SHARED_READ、SHARED_WRITE兼容,与EXCLUSIVE互斥 |
| alter table ... | EXCLUSIVE | 与其他的MDL都互斥 |
- 我们可以通过下面的SQL,来查看数据库中的元数据锁的情况:
sql
select object_type,object_schema,object_name,lock_type,lock_duration from
performance_schema.metadata_locks ;
4.4 意向锁
-
介绍
在DML操作时,会加上行锁,此时加表锁,会一行一行检查是否存在行锁。而意向锁就是,加行锁时,给表加上意向锁,从而根据意向锁的类型,判断能否加表锁。
-
意向锁分类
- 意向共享锁(IS): 由语句select ... lock in share mode添加 。 与 表锁共享锁 (read)兼容,与表锁排他锁(write)互斥。
- 意向排他锁(IX): 由insert、update、delete、select...for update添加 。与表锁共享锁(read)及排他锁(write)都互斥,意向锁之间不会互斥。
一旦事务提交了,意向共享锁、意向排他锁,都会自动释放。
可以通过以下SQL,查看意向锁及行锁的加锁情况:
sql
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from
performance_schema.data_locks;

五. 行锁
5.1 行锁的分类
行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。应用在InnoDB存储引擎中。
InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的
锁。对于行级锁,主要分为以下三类:
- 行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在
RC、RR隔离级别下都支持。

- 间隙锁(Gap Lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事
务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。

- 临键锁(Next-Key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。
在RR隔离级别下支持.

5.2 行锁
- InnoDB实现了以下两种类型的行锁:
- 共享锁(S):允许一个事务去读一行,阻止其他事务获得相同数据集的排它锁。
- 排他锁(X):允许获取排他锁的事务更新数据,阻止其他事务获得相同数据集的共享锁和排他锁。
同一行索引共享锁兼容共享锁,不兼容排他锁;而排他锁不兼容任何锁。
- 常见的SQL语句,在执行时,所加的行锁如下:

- 可以通过以下SQL,查看意向锁及行锁的加锁情况:
sql
select object_schema,object_name,index_name,lock_type,lock_mode,lock_data from
performance_schema.data_locks;
- 无索引行锁升级为表锁
当我们对表中没有索引的字段进行操作时,上面表格中的锁会升级为表锁。
当我们对该字段创建索引,就又可以正常加行锁了。
5.3 间隙锁&临键锁
防止数据幻读的情况。
-
索引查询(唯一值),给不存在的值上锁时,锁为间隙锁。
如图当我们查询19时,innoDB引擎会在29加上间隙锁。

-
索引查询(非唯一值),向右遍历时最后一个值不满足查询需求时,next-key lock 退化为间隙锁。
如图我们查询18时,因为18是非唯一的,所以我们需要给18加上临键锁和29加上间隙锁。

-
索引上的范围查询(唯一索引)--会访问到不满足条件的第一个值为止。
查询的条件为id>=21,并添加共享锁。 此时我们可以根据数据库表中现有的数据,将数据分为三个部分:
(18,29]
(29,+∞]
所以数据库数据在加锁是,29的临键锁(包含29及29之前的间隙),正无穷的临键锁(正无穷及之前的间隙)。
