# 鎖
## 鎖的種類

Mysql中鎖的分類按照不同類型的劃分可以分成不同的鎖,按照**「鎖的粒度」**劃分可以分成:**「表鎖、頁鎖、行鎖」**;按照**「使用的方式」**劃分可以分為:**「共享鎖」**和**「排它鎖」**;按照思想的劃分:**「樂觀鎖」**和**「悲觀鎖」**。
**鎖的粒度?**
**「表鎖」**是粒度最大的鎖,開銷小,加鎖快,不會出現死鎖,但是由于粒度太大,因此造成鎖的沖突幾率大,并發性能低。
**「行鎖」**是粒度最小的鎖機制,行鎖的加鎖開銷性能大,加鎖慢,并且會出現死鎖,但是行鎖的鎖沖突的幾率低,并發性能高。
**「頁鎖」**的粒度是介于行鎖和表鎖之間的一種鎖,因為頁鎖是在BDB中支持的一種鎖機制,也很少沒人提及和使用,所以這里制作概述,不做詳解。
## MyISAM
表鎖模式有兩種:**「表共享讀鎖」**和**「表獨占寫鎖」**。
#### 「表共享讀鎖」
當一個線程獲取到MyISAM表的讀鎖的時候,會阻塞其他用戶對該表的寫操作,但是不會阻塞其它用戶對該用戶的讀操作。
#### 「表獨占寫鎖」
當一個線程獲取到MyISAM表的寫鎖的時候,就會阻塞其它用戶的讀寫操作對其它的線程具有排它性。
//?顯式的添加表級讀鎖
LOCK?TABLE?表名?READ
//?顯示的添加表級寫鎖
LOCK?TABLE?表名?WRITE
//?顯式的解鎖(當一個事務commit的時候也會自動解鎖)
unlock?tables;
## MyISAM表級鎖的競爭

MyISAM存儲引擎中,**「假如同時一個讀請求,一個寫請求過來的話,它會優先處理寫請求」**,因為MyISAM存儲引擎中認為寫請求比讀請求重要。
這樣就會導致,**「假如大量的讀寫請求過來,就會導致讀請求長時間的等待,或者"線程餓死",因此MyISAM不適合運用于大量讀寫操作的場景」**,這樣會導致長時間讀取不到用戶數據,用戶體驗感極差。
當然可以通過設置`low-priority-updates`參數,設置請求鏈接的優先級,使得Mysql優先處理讀請求。
## InnoDB
除了有**「表鎖」**和**「行級鎖」**的概念,還有Gap Lock(間隙鎖)、Next-key Lock鎖,**「間隙鎖主要用于范圍查詢的時候,鎖住查詢的范圍,并且間隙鎖也是解決幻讀的方案」**。
####
#### Gap Lock(間隙鎖)

**「從上面的測試結果顯示在區間(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框架的生命周期