# 锁
## 锁的种类
![](https://img.kancloud.cn/a9/1b/a91bed62d6dade7f3683dc3044dfb3d2_989x429.png)
Mysql中锁的分类按照不同类型的划分可以分成不同的锁,按照**「锁的粒度」**划分可以分成:**「表锁、页锁、行锁」**;按照**「使用的方式」**划分可以分为:**「共享锁」**和**「排它锁」**;按照思想的划分:**「乐观锁」**和**「悲观锁」**。
**锁的粒度?**
**「表锁」**是粒度最大的锁,开销小,加锁快,不会出现死锁,但是由于粒度太大,因此造成锁的冲突几率大,并发性能低。
**「行锁」**是粒度最小的锁机制,行锁的加锁开销性能大,加锁慢,并且会出现死锁,但是行锁的锁冲突的几率低,并发性能高。
**「页锁」**的粒度是介于行锁和表锁之间的一种锁,因为页锁是在BDB中支持的一种锁机制,也很少没人提及和使用,所以这里制作概述,不做详解。
## MyISAM
表锁模式有两种:**「表共享读锁」**和**「表独占写锁」**。
#### 「表共享读锁」
当一个线程获取到MyISAM表的读锁的时候,会阻塞其他用户对该表的写操作,但是不会阻塞其它用户对该用户的读操作。
#### 「表独占写锁」
当一个线程获取到MyISAM表的写锁的时候,就会阻塞其它用户的读写操作对其它的线程具有排它性。
// 显式的添加表级读锁
LOCK TABLE 表名 READ
// 显示的添加表级写锁
LOCK TABLE 表名 WRITE
// 显式的解锁(当一个事务commit的时候也会自动解锁)
unlock tables;
## MyISAM表级锁的竞争
![](https://img.kancloud.cn/6e/16/6e161dcc9ff557663cb70205b01509c1_1042x685.png)
MyISAM存储引擎中,**「假如同时一个读请求,一个写请求过来的话,它会优先处理写请求」**,因为MyISAM存储引擎中认为写请求比读请求重要。
这样就会导致,**「假如大量的读写请求过来,就会导致读请求长时间的等待,或者"线程饿死",因此MyISAM不适合运用于大量读写操作的场景」**,这样会导致长时间读取不到用户数据,用户体验感极差。
当然可以通过设置`low-priority-updates`参数,设置请求链接的优先级,使得Mysql优先处理读请求。
## InnoDB
除了有**「表锁」**和**「行级锁」**的概念,还有Gap Lock(间隙锁)、Next-key Lock锁,**「间隙锁主要用于范围查询的时候,锁住查询的范围,并且间隙锁也是解决幻读的方案」**。
####
#### Gap Lock(间隙锁)
![](https://img.kancloud.cn/a5/59/a559fc84bb80527d24fa150c9a1e8b72_1023x856.png)
**「从上面的测试结果显示在区间(1,3\]U\[3,5)之间加了锁,是不能够新增数据行,这就是新增num=2和num=4失败的原因,但是在这个区间以外的数据行是没有加锁的,可以新增数据行」**。
根据索引的有序性,而普通索引是可以出现重复值,那么当我们第一个sesson查询的时候只出现一条数据num=3,为了解决第二次查询的时候出现幻读,也就是出现两条或者更多num=3这样查询条件的数据。
Mysql在满足where条件的情况下,给`(1,3]U[3,5)`区间加上了锁不允许插入num=3的数据行,这样就解决了幻读。
注:间隙范围的确定:当前锁定的数据的值,找到距离这个值最近的最大最小值;例如:锁定ID=10;表里最近的数据 最小id=11 最大id=18,那么这个范围就是(11,10]U[10,18)
**「主键索引(唯一索引)是否会加上间隙锁呢?」**
因为主键索引具有唯一性,不允许出现重复,那么当进行等值查询的时候只能有且只有一条数据,因此它只要锁定这条数据(锁定索引),在下次查询当前读的时候不会被删除、或者更新该数据行,也就保证了数据的一致性,所以主键索引由于他的唯一性的原因,**是不需要加间隙锁的。**
**「范围查询是否会加上间隙锁?」** 会加间隙锁
**「使用不存在的检索条件是否会加上间隙锁?」** 会加间隙锁
### next-key lock
**行锁和间隙锁共同组成**
https://www.jianshu.com/p/32904ee07e56
InnoDB中的行级锁是**「对索引加的锁,在不通过索引查询数据的时候,InnoDB就会使用表锁」**。
**「但是通过索引查询的时候是否使用索引,还要看Mysql的执行计划」**,Mysql的优化器会判断是一条sql执行的最佳策略。
若是Mysql觉得执行索引查询还不如全表扫描速度快,那么Mysql就会使用全表扫描来查询,这是即使sql语句中使用了索引,最后还是执行为全表扫描,加的是表锁。
**「共享读锁(S锁)**「和」**排它写锁(X锁)」**。
#### 「共享读锁(S锁)」
当一个事务对Mysql中的一条数据行加上了S锁,当前事务不能修改该行数据只能执行读操作,其他事务只能对该行数据加S锁不能加X锁。
#### 排它写锁(X锁)
若是一个事务对一行数据加了X锁,该事务能够对该行数据执行读和写操作,其它事务不能对该行数据加任何的锁,既不能读也不能写。
Mysql的**「悲观锁的实现是基于Mysql自身的锁机制实现,而乐观锁需要程序员自己去实现的锁机制」**,最常见的乐观锁实现就锁机制是**「使用版本号实现」**。
排他写锁(悲观锁):select ... for update;
共享读锁:select ... lock in share mode;
### 悲观锁优点与不足
悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,在只读型事务处理中由于不会产生冲突,也没必要使用锁,这样做只能增加系统负载;还有会降低了并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数。
参考:
[https://zhuanlan.zhihu.com/p/31875702]
[https://blog.csdn.net/qq\_38238296/article/details/88362999]
- 消息队列
- 为什么要用消息队列
- 各种消息队列产品的对比
- 消息队列的优缺点
- 如何保证消息队列的高可用
- 如何保证消息不丢失
- 如何保证消息不会重复消费?如何保证消息的幂等性?
- 如何保证消息消费的顺序性?
- 基于MQ的分布式事务实现
- Beanstalk
- PHP
- 函数
- 基础
- 基础函数题
- OOP思想及原则
- MVC生命周期
- PHP7.X新特性
- PHP8新特性
- PHP垃圾回收机制
- php-fpm相关
- 高级
- 设计模式
- 排序算法
- 正则
- OOP代码基础
- PHP运行原理
- zavl
- 网络协议new
- 一面
- TCP和UDP
- 常见状态码和代表的意义以及解决方式
- 网络分层和各层有啥协议
- TCP
- http
- 二面
- TCP2
- DNS
- Mysql
- 锁
- 索引
- 事务
- 高可用?高并发?集群?
- 其他
- 主从复制
- 主从复制数据延迟
- SQL的语⾔分类
- mysqlQuestions
- Redis
- redis-question
- redis为什么那么快
- redis的优缺点
- redis的数据类型和使用场景
- redis的数据持久化
- 过期策略和淘汰机制
- 缓存穿透、缓存击穿、缓存雪崩
- redis的事务
- redis的主从复制
- redis集群架构的理解
- redis的事件模型
- redis的数据类型、编码、数据结构
- Redis连接时的connect与pconnect的区别是什么?
- redis的分布式锁
- 缓存一致性问题
- redis变慢的原因
- 集群情况下,节点较少时数据分布不均匀怎么办?
- redis 和 memcached 的区别?
- 基本算法
- MysqlNew
- 索引new
- 事务new
- 锁new
- 日志new
- 主从复制new
- 树结构
- mysql其他问题
- 删除
- 主从配置
- 五种IO模型
- Kafka
- Nginx
- trait
- genergtor 生成器
- 如何实现手机扫码登录功能
- laravel框架的生命周期