# MySQL锁机制

### 博客

<https://tech.meituan.com/2014/08/20/innodb-lock.html> <https://xiaolincoding.com/mysql/buffer\\_pool/buffer\\_pool.html#buffer-pool-%E7%BC%93%E5%AD%98%E4%BB%80%E4%B9%88>

### 锁类型

* 表级锁：开销小，加锁快；不会出现死锁；锁定粒度大，发生锁冲突的概率最高，并发度最低
* 行级锁：开销大，加锁慢；会出现死锁；锁定粒度最小，发生锁冲突的概率最低，并发度也最高
* 页面锁：开销和加锁时间介于表锁和行锁之间；会出现死锁；锁定粒度介于表锁和行锁之间，并发度一般

MyISAM和MEMORY采用的是表级锁，BDB采用页面锁，InnoDB既支持行级锁，也支持表级锁，默认使用行级锁。

表共享读锁，表独占写锁（进行查询时自动加读锁，进行插入，更新，删除会自动加写锁，不需要显式写出）

```
LOCK TABLE table_name read
UNLOCK table_name
```

加了local选项，其作用就是在满足MyISAM表并发插入条件下的情况下，允许其他用户在表尾并发插入记录

```
LOCK TABLE table_name read local
UNLOCK table_name
```

```
LOCK TABLE table_name write
UNLOCK table_name
```

### MyISAM中的并发插入（Concurrent Inserts）

在一定条件下，MyISAM表也支持查询和插入的并发进行 MyISAM引擎有一个系统变量 concurrent\_insert，专门用来控制其并发插入的行为

* 当值为0时，不允许并发插入
* 当值为1时，如果表中没有空洞（即表的中间没有被删除的行），允许在一个进程读表的同时，另一个进程从表尾插入记录，这也是MySQL的默认设置
* 当为2时，无论有没有空洞，都允许在表尾并发插入

当值为2时，总是允许并发插入；同时，通过定期在系统空闲时段执行OPTIMIZE TABLE语句来整理空间碎片，收回因删除记录而产生的中间空洞。

MyISAM锁调度，优先写进程，不过可以通过一些设置来调节MyISAM的调度行为

### InnoDB锁问题

事务及其ACID属性 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190314104935744.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGVyRG9nZw==,size_16,color_FFFFFF,t_70) 并发事务处理带来的问题 ![在这里插入图片描述](https://img-blog.csdnimg.cn/201903141052387.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGVyRG9nZw==,size_16,color_FFFFFF,t_70)

### InnoDB的行锁模式及加锁方法

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190314105843793.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGVyRG9nZw==,size_16,color_FFFFFF,t_70) ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190314105923848.png)

### InnoDB行锁实现方式

InnoDB行锁是通过索引上的索引项加锁来实现的，如果没有索引，InnoDB将通过隐藏的聚簇索引来对记录加锁，InnoDB行锁分为三种情形：

* Record lock：对索引项加锁
* Gap lock：对索引项之间的间隙、第一条记录前的间隙或最后一条之后的间隙
* Next-key lock：前两种的组合，对记录及其前面的间隙加锁

行锁特性

* 在不通过索引条件查询时，会锁定表中所有的记录
* 使用相同的索引键，会出现锁冲突
* 当表中有多个索引的时候，不同的事务可以使用不同的索引锁定不同的行，不论是使用主键索引、唯一索引或普通索引，InnoDB都会使用行锁来对数据加锁
* 即便使用了索引字段，但是否使用索引来检索数据是由MySQL通过判断不同的执行计划的代价来决定的。

### Next-Key锁

当我们使用范围条件而不是相等条件检索数据，并请求共享或排他锁时，InnoDB会给复合条件的已有数据记录的索引项加锁；对于键值在条件范围内但不存在的记录，叫做“间隙”，InnoDB也会给这个间隙加锁，这种锁机制就是所谓的Next-Key锁。

使用N-K锁的目的：一方面是为了防止幻读，以满足相关隔离级别的要求；另一方面是为了满足其恢复和复制的需要。

如果使用相等条件请求给一个不存在的记录加锁，InnoDB也会使用Next-Key锁。

### 什么时候使用表锁

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190314112553272.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGVyRG9nZw==,size_16,color_FFFFFF,t_70)

### 总结

![在这里插入图片描述](https://img-blog.csdnimg.cn/20190314112525654.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGVyRG9nZw==,size_16,color_FFFFFF,t_70)

### 乐观锁和悲观锁
