溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL鎖機制的示例分析

發(fā)布時間:2021-04-01 09:30:24 來源:億速云 閱讀:202 作者:小新 欄目:MySQL數據庫

這篇文章主要介紹了MySQL鎖機制的示例分析,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

鎖在MySQL中是非常重要的一部分,鎖對MySQL的數據訪問并發(fā)有著舉足輕重的影響。鎖涉及到的知識篇幅也很多,所以要啃完并消化到自己的肚子里,是需要靜下心好好反反復復幾遍地細細品味。本文是對鎖的一個大概的整理,一些相關深入的細節(jié),還是需要找到相關書籍來繼續(xù)夯實。

MySQL鎖機制的示例分析

鎖的認識

1.1 鎖的解釋

計算機協調多個進程或線程并發(fā)訪問某一資源的機制。

1.2 鎖的重要性

在數據庫中,除傳統(tǒng)計算資源(CPU、RAM、I\O等)的爭搶,數據也是一種供多用戶共享的資源。
如何保證數據并發(fā)訪問的一致性,有效性,是所有數據庫必須要解決的問題。
鎖沖突也是影響數據庫并發(fā)訪問性能的一個重要因素,因此鎖對數據庫尤其重要。

1.3 鎖的缺點

加鎖是消耗資源的,鎖的各種操作,包括獲得鎖、檢測鎖是否已解除、釋放鎖等 ,都會增加系統(tǒng)的開銷。

1.4 簡單的例子

現如今網購已經特別普遍了,比如淘寶雙十一活動,當天的人流量是千萬及億級別的,但商家的庫存是有限的。
系統(tǒng)為了保證商家的商品庫存不發(fā)生超賣現象,會對商品的庫存進行鎖控制。當有用戶正在下單某款商品最后一件時,
系統(tǒng)會立馬對該件商品進行鎖定,防止其他用戶也重復下單,直到支付動作完成才會釋放(支付成功則立即減庫存售罄,支付失敗則立即釋放)。

鎖的類型

2.1 表鎖

種類

讀鎖(read lock),也叫共享鎖(shared lock)
針對同一份數據,多個讀操作可以同時進行而不會互相影響(select)
寫鎖(write lock),也叫排他鎖(exclusive lock)
當前操作沒完成之前,會阻塞其它讀和寫操作(update、insert、delete)

存儲引擎默認鎖

MyISAM

特點

1. 對整張表加鎖
2. 開銷小
3. 加鎖快
4. 無死鎖
5. 鎖粒度大,發(fā)生鎖沖突概率大,并發(fā)性低
結論
1. 讀鎖會阻塞寫操作,不會阻塞讀操作
2. 寫鎖會阻塞讀和寫操作
建議
MyISAM的讀寫鎖調度是寫優(yōu)先,這也是MyISAM不適合做寫為主表的引擎,因為寫鎖以后,其它線程不能做任何操作,大量的更新使查詢很難得到鎖,從而造成永遠阻塞。

2.2 行鎖

種類

讀鎖(read lock),也叫共享鎖(shared lock)
允許一個事務去讀一行,阻止其他事務獲得相同數據集的排他鎖
寫鎖(write lock),也叫排他鎖(exclusive lock)
允許獲得排他鎖的事務更新數據,阻止其他事務取得相同數據集的共享鎖和排他鎖
意向共享鎖(IS)
一個事務給一個數據行加共享鎖時,必須先獲得表的IS鎖
意向排它鎖(IX)
一個事務給一個數據行加排他鎖時,必須先獲得該表的IX鎖
存儲引擎默認鎖
InnoDB
特點
1. 對一行數據加鎖
2. 開銷大
3. 加鎖慢
4. 會出現死鎖
5. 鎖粒度小,發(fā)生鎖沖突概率最低,并發(fā)性高
事務并發(fā)帶來的問題
1. 更新丟失
解決:讓事務變成串行操作,而不是并發(fā)的操作,即對每個事務開始---對讀取記錄加排他鎖
2. 臟讀
解決:隔離級別為Read uncommitted
3. 不可重讀
解決:使用Next-Key Lock算法來避免
4. 幻讀
解決:間隙鎖(Gap Lock)

2.3 頁鎖

開銷、加鎖時間和鎖粒度介于表鎖和行鎖之間,會出現死鎖,并發(fā)處理能力一般(此鎖不做多介紹)

如何上鎖?

3.1 表鎖

隱式上鎖(默認,自動加鎖自動釋放)
select //上讀鎖
insert、update、delete //上寫鎖
顯式上鎖(手動)
lock table tableName read;//讀鎖
lock table tableName write;//寫鎖
解鎖(手動)
unlock tables;//所有鎖表
session01session02
lock table teacher read;//上讀鎖
select * from teacher;  //可以正常讀取select * from teacher;//可以正常讀取
update teacher set name = 3 where id =2;//報錯因被上讀鎖不能寫操作update teacher set name = 3 where id =2;//被阻塞
unlock tables;//解鎖

update teacher set name = 3 where id =2;//更新操作成功
session01session02
lock table teacher write;//上寫鎖
select * from teacher;  //可以正常讀取select * from teacher;//被阻塞
update teacher set name = 3 where id =2;//可以正常更新操作update teacher set name = 4 where id =2;//被阻塞
unlock tables;//解鎖

select * from teacher;//讀取成功

update teacher set name = 4 where id =2;//更新操作成功

3.2 行鎖

隱式上鎖(默認,自動加鎖自動釋放)

select //不會上鎖
insert、update、delete //上寫鎖
顯式上鎖(手動)
select * from tableName lock in share mode;//讀鎖
select * from tableName for update;//寫鎖
解鎖(手動)
1. 提交事務(commit)
2. 回滾事務(rollback)
3. kill 阻塞進程
session01session02
begin;
select * from teacher where id = 2 lock in share mode;//上讀鎖

select * from teacher where id = 2;//可以正常讀取
update teacher set name = 3 where id =2;// 可以更新操作update teacher set name = 5 where id =2;//被阻塞
commit;

update teacher set name = 5 where id =2;//更新操作成功
session01session02
begin;
select * from teacher where id = 2 for update;//上寫鎖

select * from teacher where id = 2;//可以正常讀取
update teacher set name = 3 where id =2;// 可以更新操作update teacher set name = 5 where id =2;//被阻塞
rollback;

update teacher set name = 5 where id =2;//更新操作成功
為什么上了寫鎖,別的事務還可以讀操作?
因為InnoDB有MVCC機制(多版本并發(fā)控制),可以使用快照讀,而不會被阻塞。

行鎖的實現算法

4.1 Record Lock鎖

單個行記錄上的鎖
Record Lock總是會去鎖住索引記錄,如果InnoDB存儲引擎表建立的時候沒有設置任何一個索引,這時InnoDB存儲引擎會使用隱式的主鍵來進行鎖定

4.2 Gap Lock鎖

當我們用范圍條件而不是相等條件檢索數據,并請求共享或排他鎖時,InnoDB會給符合條件的已有數據記錄的索引加鎖,對于鍵值在條件范圍內但并不存在的記錄。

優(yōu)點:解決了事務并發(fā)的幻讀問題
不足:因為query執(zhí)行過程中通過范圍查找的話,他會鎖定爭個范圍內所有的索引鍵值,即使這個鍵值并不存在。
間隙鎖有一個致命的弱點,就是當鎖定一個范圍鍵值之后,即使某些不存在的鍵值也會被無辜的鎖定,而造成鎖定的時候無法插入鎖定鍵值范圍內任何數據。在某些場景下這可能會對性能造成很大的危害。

4.3 Next-key Lock鎖

同時鎖住數據+間隙鎖
在Repeatable Read隔離級別下,Next-key Lock 算法是默認的行記錄鎖定算法。

4.4 行鎖的注意點

1. 只有通過索引條件檢索數據時,InnoDB才會使用行級鎖,否則會使用表級鎖(索引失效,行鎖變表鎖)
2. 即使是訪問不同行的記錄,如果使用的是相同的索引鍵,會發(fā)生鎖沖突
3. 如果數據表建有多個索引時,可以通過不同的索引鎖定不同的行

如何排查鎖?

5.1 表鎖

查看表鎖情況
show open tables;

MySQL鎖機制的示例分析

表鎖分析
show status like 'table%';

MySQL鎖機制的示例分析

1. table_locks_waited
出現表級鎖定爭用而發(fā)生等待的次數(不能立即獲取鎖的次數,每等待一次值加1),此值高說明存在著較嚴重的表級鎖爭用情況
2. table_locks_immediate
產生表級鎖定次數,不是可以立即獲取鎖的查詢次數,每立即獲取鎖加1

5.2 行鎖

行鎖分析

show status like 'innodb_row_lock%';

MySQL鎖機制的示例分析

1. innodb_row_lock_current_waits //當前正在等待鎖定的數量
2. innodb_row_lock_time //從系統(tǒng)啟動到現在鎖定總時間長度
3. innodb_row_lock_time_avg //每次等待所花平均時間
4. innodb_row_lock_time_max //從系統(tǒng)啟動到現在等待最長的一次所花時間
5. innodb_row_lock_waits //系統(tǒng)啟動后到現在總共等待的次數
information_schema庫
1. innodb_lock_waits表
2. innodb_locks表
3. innodb_trx表
優(yōu)化建議
1. 盡可能讓所有數據檢索都通過索引來完成,避免無索引行鎖升級為表鎖
2. 合理設計索引,盡量縮小鎖的范圍
3. 盡可能較少檢索條件,避免間隙鎖
4. 盡量控制事務大小,減少鎖定資源量和時間長度
5. 盡可能低級別事務隔離

死鎖

6.1 解釋

指兩個或者多個事務在同一資源上相互占用,并請求鎖定對方占用的資源,從而導致惡性循環(huán)的現象

6.2 產生的條件

1. 互斥條件:一個資源每次只能被一個進程使用
2. 請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放
3. 不剝奪條件:進程已獲得的資源,在沒有使用完之前,不能強行剝奪
4. 循環(huán)等待條件:多個進程之間形成的一種互相循環(huán)等待的資源的關系

6.1 解決

1. 查看死鎖:show engine innodb status \G
2. 自動檢測機制,超時自動回滾代價較小的事務(innodb_lock_wait_timeout 默認50s)
3. 人為解決,kill阻塞進程(show processlist)
4. wait for graph 等待圖(主動檢測)

6.1 如何避免

1. 加鎖順序一致,盡可能一次性鎖定所需的數據行
2. 盡量基于primary(主鍵)或unique key更新數據
3. 單次操作數據量不宜過多,涉及表盡量少
4. 減少表上索引,減少鎖定資源
5. 盡量使用較低的隔離級別
6. 盡量使用相同條件訪問數據,這樣可以避免間隙鎖對并發(fā)的插入影響
7. 精心設計索引,盡量使用索引訪問數據
8. 借助相關工具:pt-deadlock-logger

樂觀鎖與悲觀鎖

MySQL鎖機制的示例分析

7.1 悲觀鎖

解釋
假定會發(fā)生并發(fā)沖突,屏蔽一切可能違反數據完整性的操作
實現機制
表鎖、行鎖等
實現層面
數據庫本身
適用場景
并發(fā)量大

7.2 樂觀鎖

解釋
假設不會發(fā)生并發(fā)沖突,只在提交操作時檢查是否違反數據完整性
實現機制
提交更新時檢查版本號或者時間戳是否符合
實現層面
業(yè)務代碼
適用場景
并發(fā)量小

感謝你能夠認真閱讀完這篇文章,希望小編分享的“MySQL鎖機制的示例分析”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業(yè)資訊頻道,更多相關知識等著你來學習!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI