目录
概述
、
RAM
、
I/O
等)的争用以外,数据也是一种供许多用户共享的 资源。为保证数据的一致性,需要对
并发操作进行控制
,因此产生了
锁
。同时
锁机制
也为实现
MySQL 的各个隔离级别提供了保证。
锁冲突
也是影响数据库
并发访问性能
的一个重要因素。所以锁对数据库而言显得尤其重要,也更加复杂。
锁的不同角度分类
为了尽可能提高数据库的并发度,每次锁定的数据范围越小越好,理论上每次只锁定当前操作的数据的方案会得到最大的并发度,但是管理锁是很 耗资源 的事情(涉及获取、检查、释放锁等动作)。因此数据库系统需要在高并发响应 和系统性能 两方面进行平衡,这样就产生了“锁粒度(Lock granularity)”的概念。
对一条记录加锁影响的也只是这条记录而已,我们就说这个锁的粒度比较细;其实一个事务也可以在 表级别 进行加锁,自然就被称之为 表级锁 或者 表锁,对一个表加锁影响整个表中的记录,我们就说这个锁的粒度比较粗。锁的粒度主要分为表级锁,页级锁和行锁。
Mysql中的锁根据锁粒度划分大致可分为以下三种:
- 表级锁
- 表级别的S锁、X锁
- 意向锁
- 自增锁
- MDL锁
- 行级锁
- Record Locks
- Gap Locks
- Next-Key Locks
- 插入意向锁
- 页级锁
示意图如下:
一、表级锁
1.表级别的S锁、X锁
存储引擎提供的表级别的
S
锁
和
X
锁 ,
而会选择力度更小的
行级锁
。只会在一些特殊情况下,比方说
崩溃恢复
过程中用到。比如,在系统变量
autocommit=0
,
innodb_table_locks = 1
时,
手动
获取。InnoDB存储引擎提供的表
t
的
S
锁
或者
X
锁
可以这么写:
- LOCK TABLES teacher READ :InnoDB存储引擎会对表 teacher 加表级别的 S锁 。
- LOCK TABLES teacher WRITE :InnoDB存储引擎会对表 teacher 加表级别的 X锁 。
存储引擎的表上使用
LOCK TABLES
这样的手动锁表语句,因为它们只会降低并发能力而不能提供额外的保护。InnoDB
的厉害之处还是实现了更细粒度的
行锁
,关于InnoDB表级别的
S
锁
和
X
锁
大家了解即可。
2.意向锁
支持
多粒度锁(
multiple granularity locking
)
,即允许多种粒度的锁共存,比如
行级锁
与
表级锁
共存,而
意向
锁
就是其中的一种
表锁
。而意向锁的存在也使得行级锁的性能更上一层楼
- 意向锁的存在是为了协调行锁和表锁的关系,支持多粒度(表锁与行锁)的锁并存。
- 意向锁是一种 不与行级锁冲突表级锁,这一点非常重要。
- 表明“某个事务正在某些行持有了锁或该事务准备去持有锁”
① 意向锁分为两种:
- 意向共享锁(intention shared lock, IS):事务有意向对表中的某些行加共享锁(S锁)
-- 事务要获取某些行的 S 锁,必须先获得表的 IS 锁。
SELECT column FROM table ... LOCK IN SHARE MODE;
- 意向排他锁(intention exclusive lock, IX):事务有意向对表中的某些行加排他锁(X锁)
-- 事务要获取某些行的 X 锁,必须先获得表的 IX 锁。
SELECT column FROM table ... FOR UPDATE;
自己维护的
,用户无法手动操作意向锁,在为数据行加共享
/
排他锁之前, InooDB 会先获取该数据行
所在数据表的对应意向锁
。
② 意向锁解决的问题:
如果我们给某一行数据加上了排他锁,数据库会自动给更大一级空间,比如数据页或数据表加上意向锁,告诉其他人这个数据页或数据表已经有人上过排他锁了。
举例:在数据库数据量大时,想给某个表加锁时无需一行一行查找是否上锁,只需查看表上是否有意向锁。
③ 演示:
创建表teacher,并插入数据
开启一个事务:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#下面的查询语句为id为5的行加上了X锁,同时teacher表上会加上意向锁IX
mysql> select * from teacher where id = 5 for update;
+----+--------+
| id | name |
+----+--------+
| 5 | 钱七 |
+----+--------+
1 row in set (0.00 sec)
开启另一个事务:
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#以下命令想在teacher表上添加S锁,在新的事务中执行发现阻塞
mysql> lock tables teacher read;
因为在表中某一行上加了X/S锁后表自动加上意向锁IX/IS,所以在表上添加S锁或者X锁都会被阻塞
④ 意向锁的兼容互斥性
意向锁之间是相互兼容的,虽然意向锁和意向锁互相兼容,但是会与表级别的普通的排他/共享锁互斥。
这里的共享锁和排他锁指的是表级别的,意向锁不会与行级别的共享/排他锁互斥。
/
排他锁互斥!正因为如此,意向锁并不会影响到多个事务对不同数据行加排他锁时的并发性。
3. 自增锁(AUTO-INC锁)
① 举例:
我们创建老师表的同时为id字段加上自增
CREATE TABLE `teacher` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
这意味着我们在插入时可以不指定id的值,插入SQL语句如下:
INSERT INTO teacher(name) VALUES('张三'),('李四');
id
列显式赋值,所以系统会自动为它赋上递增的值,结果如下所示。
② 插入模式
上面我们演示的只是一种简单的插入模式,所有插入数据的方式总共分为三类,分别是
Simple inserts
”
,
“
Bulk inserts
”
和
“
Mixed
–
mode inserts
”
。
1. “Simple inserts” (简单插入)
我们上面演示的就是简单插入,即可以 预先确定要插入的行数 (当语句被初始处理时)的语句。包括没有嵌套子查询的单行和多行 INSERT…VALUES() 和 REPLACE 语句。
(批量插入)
比如
INSERT … SELECT , REPLACE … SELECT
和
LOAD DATA
这种 事先不知道要插入的行数
(和所需自动递增值的数量)的语句。但不包括纯INSERT
。
InnoDB
在每处理一行,为
AUTO_INCREMENT
列 分配一个新值。
(混合模式插入)
语句但是指定部分新行的自动递增值。例如
INSERT INTO teacher(id,name) VALUES (1,’a’), (NULL,’b’), (5,’c’), (NULL,’d’);
只是指定了部分
id
的值。另一种类型的
“
混合模式插入”
是
INSERT … ON DUPLICATE KEY UPDATE
。
③ 锁定模式
有三种取值,分别对应与不同锁定模式:
1
)
innodb_autoinc_lock_mode = 0(“
传统
”
锁定模式
)
语句都会获得一个特殊的表级
AUTO-INC
锁,用于插入具有 AUTO_INCREMENT列的表。这种模式其实就如我们上面的例子,即每当执行
insert
的时候,都会得到一个 表级锁(AUTO-INC
锁
)
,使得语句中生成的
auto_increment
为顺序,且在
binlog
中重放的时候,可以保证 master与
slave
中数据的
auto_increment
是相同的。因为是表级锁,当在同一时间多个事务中执行
insert
的 时候,对于AUTO-INC
锁的争夺会
限制并发
能力。
2
)
innodb_autoinc_lock_mode = 1(“
连续
”
锁定模式
)
之前,连续锁定模式是
默认
的。
仍然使用
AUTO-INC
表级锁,并保持到语句结束。这适用于所有
INSERT … SELECT,
REPLACE … SELECT
和
LOAD DATA
语句。同一时刻只有一个语句可以持有
AUTO-INC
锁。
(要插入的行数事先已知),则通过在
mutex
(轻量锁)
的控制下获得所需数量的 自动递增值来避免表级AUTO-INC
锁, 它只在分配过程的持续时间内保持,而不是直到语句完成。不使用 表级AUTO-INC
锁,除非
AUTO-INC
锁由另一个事务保持。如果另一个事务保持
AUTO-INC
锁,则
“Simple inserts”等待
AUTO-INC
锁,如同它是一个
“bulk inserts”
。
3
)
innodb_autoinc_lock_mode = 2(“
交错
”
锁定模式
)
开始,交错锁模式是
默认
设置。
保证
在所有并发执行的所有类型的
insert
语句中是
唯一
且
单调递增
的。但是,由于多个语句可以同时生成数字(即,跨语句交叉编号),
为任何给定语句插入的行生成的值可能
不是连续的。
4. 元数据锁(MDL锁)
meta data lock
,简称
MDL
锁,属于表锁范畴。
MDL
的作用是,保证读写的正确性。比如,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个
表结构做变更
,增加了一 列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。
当对一个表做增删改查操作的时候,加
MDL
读锁;当要对表做结构变更操作的时候,加
MDL
写
锁。
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
#表上会自动加上MDL读锁
mysql> select * from teacher;
+----+--------+
| id | name |
+----+--------+
| 1 | 张三 |
| 2 | 李四 |
| 3 | 王五 |
| 4 | 赵六 |
| 5 | 钱七 |
+----+--------+
5 rows in set (0.00 sec)
验证:
② MDL锁的并发性
二、行级锁
行锁(RowLock)也称为记录锁,顾名思义,就是锁住某一行(某条记录row)。需要的注意的是,MySQL服务器层并没有实现行锁机制,行级锁只在存储引擎层实现。
- 优点:锁定力度小,发生 锁冲突概率低,可以实现的并发度高。
- 缺点:对于锁的开销比较大,加锁会比较慢,容易出现 死锁 情况。
InnoDB与MvISAM的最大不同有两点:一是支持事务(TRANSACTION);一是采用了行级锁。
1. 记录锁
LOCK_REC_NOT_GAP
。比如我们把
id
值为
8
的 那条记录加一个记录锁的示意图如图所示。仅仅是锁住了id
值为
8
的记录,对周围的数据没有影响。
S
锁和
X
锁之分的,称之为
S
型记录锁
和
X
型记录锁
。
- 当一个事务获取了一条记录的S型记录锁后,其他事务也可以继续获取该记录的S型记录锁,但不可以继续获取X型记录锁;
- 当一个事务获取了一条记录的X型记录锁后,其他事务既不可以继续获取该记录的S型记录锁,也不可以继续获取X型记录锁。
2.间隙锁
在
REPEATABLE READ
隔离级别下是可以解决幻读问题的,解决方案有两种,可以使用
MVCC
方案解决,也可以采用
加锁
方案解决。但是在加锁的情况下,对于尚未存在的记录也就谈不上加锁了。
Gap Locks
的锁,官方的类型名称为:
LOCK_GAP
,我们可以简称为
gap
锁
。
id
值为
8
的记录加了
gap
锁,意味着
不允许别的事务在
id
值为
8
的记录前边的间隙插入新记录
,其实就是 id列的值
(3, 8)
这个区间的新记录是不允许立即插入的。比如,有另外一个事务再想插入一条
id
值为
4
的新 记录,它定位到该条新记录的下一条记录的id
值为
8
,而这条记录上又有一个
gap
锁,所以就会阻塞插入 操作,直到拥有这个gap
锁的事务提交了之后,
id
列的值在区间
(3, 8)
中的新记录才可以被插入。
锁的提出仅仅是为了防止插入幻影记录而提出的
3.临键锁
锁住某条记录
,又想
阻止
其他事务在该记录前边的
间隙插入新记录
,所以
InnoDB
就提 出了一种称之为
Next
–
Key Locks
的锁,官方的类型名称为:
LOCK_ORDINARY
,我们也可以简称为
next-
key
锁 ,
相当于记录所与间隙锁的结合
。
Next-Key Locks
是在存储引擎
innodb
、事务级别在
可重复读
的情况下使用的数据库锁, innodb默认的锁就是
Next-Key locks
。
begin;
select * from student where id <=8 and id > 3 for update;
4. 插入意向锁
插入
一条记录时需要判断一下插入位置是不是被别的事务加了
gap
锁
(
next
–
key
锁
也包含
gap
锁
),如果有的话,插入操作需要等待,直到拥有
gap
锁
的那个事务提交。但是
InnoDB
规
,表明有事务想在某个
间隙
中
插入
新记录,但是 现在在等待。InnoDB
就把这种类型的锁命名为
Insert Intention Locks
,官方的类型名称为:
,我们称为
插入意向锁
。插入意向锁是一种
Gap
锁
,不是意向锁,在
insert 操作时产生。
INSERT
操作产生的一种间隙锁
。
插入意向锁并不会阻止别的事务继续获取该记录上任何类型的锁。
三、页锁
页的粒度
上进行锁定,锁定的数据资源比行锁要多,因为一个页中可以有多个行记录。当我 们使用页锁的时候,会出现数据浪费的现象,但这样的浪费最多也就是一个页上的数据行。
页锁的开销
介于表锁和行锁之间,会出现死锁。锁定粒度介于表锁和行锁之间,并发度一般。
锁空间的大小是有限的
。当某个层级的锁数量 超过了这个层级的阈值时,就会进行
锁升级
。锁升级就是用更大粒度的锁替代多个更小粒度的锁,比如 InnoDB 中行锁升级为表锁,这样做的好处是占用的锁空间降低了,但同时数据的并发度也下降了。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/118512.html