MySQL具体有哪些锁以及锁的知识点

主要参考图解小林,总结一个笔记

一、锁分类

1. 按粒度分

全局锁 表锁 页锁 行锁
粒度最大 粒度其次 粒度较小 粒度最小
不会死锁 不会死锁 会死锁 会死锁
加锁开销小,并发度极低 开销较小,并发度较低 开销较大,并发度略高 开销很大,并发度高

2. 类别分

共享锁/读锁 独占锁/写锁
可以同时加多个 只能加一个

 3. 乐观锁、悲观锁

乐观锁 悲观锁
先做着,最后提交才做锁定 先锁着,再进行事务操作
假设不会发生冲突

假设会发生冲突

多读场景 多写场景
省去锁的开销,增大吞吐量 降低性能,提升安全性

二、全局锁

使用命令为 flush tables with read lock
释放锁命令 unlock tables 

2.1 全局锁应用

全局锁主要应用于全库逻辑备份

2.2 全局锁缺点

锁粒度太大,加上全局锁,整个数据库只处于可读状态。同时有关数据库的业务也无法进行

2.3 如何规避全局锁的缺点

如果是innodb引擎,其可重复读隔离级别可以支持事务,且会在事务前创建一个读视图,这样在事务期间,就面对这个read view读视图来进行数据库操作,同时由于MVCC(多版本并发控制),备份期间仍然可以对数据进行更新操作。

如果是myisam引擎,其不支持事务,就无法像innodb那样操作,只能通过加上全局锁的操作,但是如果有从库,可以对从库进行全库逻辑备份,主库仍然可以执行相应操作,但要考虑binlog日志

三、表级锁

3.1 表级锁的种类

表锁         元数据锁        意向锁        AUTO-INC锁

3.2 表锁加锁解锁语句

加锁  lock tables a  read;     表级别共享锁   读锁
加锁  lock tables b  write;    表级别独占锁   写锁
解锁  unlock  tables;

3.3 元数据锁 (MDL)

我们不需要显式的进行加锁,这个元数据锁加锁是自动的

当我们对数据库进行CURD操作就是加MDL读锁

当我们对数据库的表结构进行变更时其实加的是MDL写锁

CURD操作就是创建(Create)、更新(Update)、读取(Read)和 删除(Delete) 操作

CURD 定义了用于处理数据的基本原子操作

MDL是在事务提交时自动释放,在事务期间,MDL会一直持有。

3.4 意向锁

在使用 InnoDB 引擎的表里对某些记录加上「共享锁」之前,需要先在表级别加上一个「意向共享锁」;
在使用 InnoDB 引擎的表里对某些纪录加上「独占锁」之前,需要先在表级别加上一个「意向独占锁」; 

意向共享锁和意向独占锁是表级锁,不会和行级的共享锁和独占锁发生冲突,而且意向锁之间也不会发生冲突,只会和共享表锁(lock tables ... read)和独占表锁(lock tables ... write)发生冲突。

所以意向锁的目的主要是为了快速判断表里是否有数据被加锁

3.5 AUTO-INC 锁

AUTO-INC 锁是特殊的表锁机制,锁不是再一个事务提交后才释放,而是再执行完插入语句后就会立即释放。其仍然为表锁。

但是这种机制会影响并发性能,所以innodb引擎提供了一种轻量级锁完成自增,只要申请自增主键后就释放锁,并不需要等语句执行后才释放。

但这个在binlog采用statement格式时会产生主从不一致的错误,所以需要把binlog日志的文件格式改为row格式。当 innodb_autoinc_lock_mode = 2 时,并且 binlog_format = row,既能提升并发性,又不会出现数据一致性问题。

四、行级锁

行锁是怎么实现的

▪ 通过给索引上的索引项加锁来实现的

▪ InnoDB这种⾏锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使⽤⾏级锁, 否则,InnoDB将使⽤表锁!

行级锁的类型主要有三类:

1. Record Lock,记录锁,也就是仅仅把一条记录锁上;
2. Gap Lock,间隙锁,锁定一个范围,但是不包含记录本身;
3. Next-Key Lock:Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

Record Lock Gap Lock Next-Key Lock
含义 记录锁,锁的记录本身 间隙锁,锁的是一个范围,不锁记录本身 临键锁,既锁记录本身,又锁间隙
锁单点记录 前开后开 前开后闭

 

普通select语句是不会对记录加锁的,因为它属于快照读。如果要在查询时对记录加行锁,可以使用下面这两个方式,这种查询会加锁的语句称为锁定读

//对读取的记录加共享锁
select ... lock in share mode;

//对读取的记录加独占锁
select ... for update;

4.1 记录锁

记录锁有S和X之分,S相当于共享锁/读锁,X相当于独占锁/写锁

锁的是这条行记录

4.2 间隙锁

Gap Lock 称为间隙锁,只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。锁住是间隙,不允许插入,如果在间隙锁加锁期间,执行插入语句会被阻塞。

间隙锁虽然存在 X 型间隙锁和 S 型间隙锁,但是并没有什么区别,间隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的。

4.3 临键锁

Next-Key Lock 称为临键锁,是 Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。

在innodb可重复读隔离级别上,对于当前读,就是通过MVCC和临键锁来解决大多数幻读问题的。

4.4 插入意向锁

插入意向锁并不属于表级别的意向锁,其实属于行级锁,可认为是一种特殊的间隙锁。所以插入意向锁是会跟间隙锁互斥的。

一个事务在插入一条记录的时候,需要判断插入位置是否已被其他事务加了间隙锁(next-key lock 也包含间隙锁)。

如果有的话,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。

五、一些锁的知识点

5.1 为什么加锁?

▪ 并发情况下产⽣多个事务同时存取同⼀数据的情况,不加控制就会产⽣读取或存储不正确,破坏⼀致性

▪ 保证多用户环境下保证数据库完整性和⼀致性

5.2 乐观锁的实现方式?

▪ 版本号机制:多⼀个version字段,必须版本号⼀制才能更新数据

▪ CAS(compare and swap)

5.3 什么场景下产生间隙锁?

▪ eg场景:试图去锁定某⼀条数据,⽤的是for update,这⼀条数据不存在,此时产⽣的什么锁(间隙锁)

5.4 死锁?

▪ 多个事务在同⼀资源上互相占⽤,锁定对方请求的资源,恶性循环

▪ 解决死锁⽅法:⼀个事务中尽可能⼀次锁定所需要的所有资源;升级锁的粒度,通过表级锁减少死锁产⽣概率;不同程序并发使用多个表,尽量约定以相同的顺序

5.5 隔离级别与锁的关系?

▪ 读未提交:不加共享锁

▪ 读提交:加共享锁,语句执⾏完后释放

▪ 可重复读:加共享锁,事务完成前不释放

▪ 串行化:锁定整个范围的键,⼀直持有锁直到事务完成

未完待续...

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