前言
本文讲述 mysql 锁定义,lock 与 latch 区别,Innodb 中的锁,强制开启 S / X 锁,自增长锁,行锁的 3 中算法,锁降级等,次要参照来自《MYSQL 技术底细 第 2 版》这本书,以及参杂了本人的一些了解。
锁定义 / 作用
为反对对 共享资源 的并发拜访,保证数据的 一致性
与完整性
,数据库所提供的一种 束缚机制。不同的数据库和不同的引擎有着不同实现形式及反对度,可分为行,页,表锁。(MyISAM 是表锁,SQL SERVER 是行级锁,InnoDB 默认也是行级锁)
行锁 | 页锁 | 表锁 | |
---|---|---|---|
MyISAM | √ | ||
Innodb | √ | √ | |
BDB | √ | ||
SQL Server | √ | √ |
前三个都是 MYSQL 的不同引擎。
lock 与 latch(门闩 shuan)
latch 实用于短期锁定的
轻量级锁
(门闩不防盗嘛),锁定工夫过长时,性能会十分差。
lock 的对象是事务,锁定的是数据库中的对象: 行、页、表,锁在 commit 或 rollback 时才会开释。
latch 分为 mutex(互斥锁)和 rwlock(读写锁),用于保障 并发线程
操作临界资源 (能够了解为共享资源) 的正确性。
latch 是面向数据库系统底层的,目前没找供用户开发的 api,除非 DBA,一般开发者根本用不到,理解即可。
lock | latch | |
---|---|---|
对象 | 事务 | 线程 |
持续时间 | 整个事务 | 临界资源 |
模式 | 行,页,表锁 | mutex,rwlock |
保留在 | lock manager 的哈希表中 | 数据结构的对象中 |
mysql innodb 中:
查看 latch 命令: `show engine innodb latch`
查看 lock 命令: `show engine innodb status`
Innodb 引擎中的锁
innodb 反对行锁和表锁(不反对表锁),默认为行锁。
两种行级锁:
- 共享锁(S lock):容许事务读 1 行
- 排他锁(X lock):容许事务删除或更新 1 行
在 A 取得 S 锁后,B 可获 S 锁,但不能加 X,否则 A 会阻塞。(读不影响数据)
在 A 取得 X 锁后,B 不能再取得任何锁。(批改必须独占)
S 锁能够了解为读锁,X 锁能够了解为独占锁,且 X 优先级高于 S。
Innodb 反对多粒度锁定,容许行级、表级上的锁同时存在。(Innodb 不反对页级锁)为此推出一种新的锁形式 意向锁(Intention Lock): 将锁定的对象分为多个档次,以满足事务在更细的细粒度上加锁。
一句话概括就是,对下层对象 (页,表) 加同样的意向锁(IS/IX)。同样的意思就是记录加 S,下层对象就加 IS;同理,记录加 X,下层对象就加 IX。
所有兼容状况:(兼容就是能获取,不兼容就是要期待阻塞)
很显著,是对称矩阵哦
一致性非锁定读
一致性非锁定读 (consistent nolocking read):指的是在读取被加 X 锁的行时,不须要期待行锁的开释,会去读它的快照(snapshot)。
一个行有多个快照数据,到底读哪一个呢?
READ COMMITED 是读最新的,READ REPEATEABLE(Innodb 默认隔离级别)是读的是 本人 事务 begin 前的。(这里的场景是开启两个事务,一个查,一个改,有先后。)READ COMMITD 会毁坏隔离性(Isolation)
一致性锁定读 – 强制开启锁
尽管可反复读(默认隔离级别)保障了隔离性,但为了确保数据的一致性,咱们能够显式 强制加锁
:
- SELECT … IN SHARE MODE
- SELECT … FOR UPDATE
下面的 in share mode
是加的 S 锁。for update
是加的 X 锁。
自增长锁
对字段设置 auto_incrment 时,自增计算器会保留在表中,锁会在 insert 语句之后,事务 commit 之前开释。(非凡的机制,为进步插入性能,没有抉择事务完结再开释,而是 Insert 后)。前面 MYSQL 还新增了 innodb_autoinc_mode
来进一步管制自增长。
注:Innodb 下自增列必须是索引,而且是索引的第一列(组合索引状况下),否则抛出异样。MyISAM 没有这要求。
行锁的 3 种算法
- Record Lock : 记录锁,锁定本人的记录
- Gap Lock:沟锁,锁本人左近的范畴,不包含本人记录(开区间)
- Next-key Lock:范畴 + 本人,Record+Gap 联合(闭区间)
Record Lock 是锁住 索引记录
,主键也是索引之一。
Next-key 是 行查问
select 默认采纳的锁算法,如有索引:10,13,20。则锁区间为:(-∞,10],(10,13],(13,20],(20,+∞)。
显知,gap 的话就蕴含本人,]变成了)。
next-key 这里的 next 指的就是右区间为闭区间,推理:previous-key 指的是左区间闭合。
注:主动降级:若索引中含有惟一属性(** 惟一 ** 索引),则 next-key 会主动降级为 record-key。(范畴锁——> 只锁本人)
next-key 机制的创造是为了解决 Phantom problem
(幻像问题),是的 mysql 能够不到 serializable 就能够解决幻读。
幻像 :一个事务 A 在未提交时,两次 sql 的执行的后果的 数据条数 不一样,B 向其中批改的数据被 A 在第二次读走了。违反了隔离性。
脏读: A 读到了 B 中 未提交
的数据,若 B 之后回滚了,则读到了脏数据。
不可反复读: B 对 A 读到的值进行了批改,A 第二次读到的 数据值 变了。
锁降级(lock escalation)
定义:锁的粒度升高。如:行锁——> 页锁——> 表锁
作用:锁是罕见资源,降级是为了提高效率,避免零碎应用太多内存来保护锁。
Innodb 存储引擎不存在锁降级。因为它不是依据记录来产生行锁,而是依据事务拜访的每个页来治理锁,采纳 位图
形式。锁住一个页的一条与锁住多条的开销一样。
这里的 ` 页来治理锁 ` 和下面 `innodb 不反对页锁 ` 有点绕,我也没了解,我前面去查证一下。