本文主要從共享鎖(S鎖)和獨佔鎖(X鎖)出發,詳細說明兩種鎖的加鎖機制,以及死鎖如何產生。mysql
上一篇文章中咱們已經講解了共享鎖和獨佔鎖的基本概念,我這邊再詳細將一下。sql
共享鎖。
S鎖 | X鎖 | |
---|---|---|
S鎖 | 兼容 | 不兼容 |
X鎖 | 不兼容 | 不兼容 |
瞭解了S鎖和X鎖,那麼咱們來看看什麼是死鎖吧。
讓咱們來複現下死鎖的過程,以便更好理解。建議能夠根據本身理解來複現死鎖過程,並分析緣由加深理解。否則變成:
眼睛: 我會了。
腦子: 不,你不會。數據庫
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
`addresss` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT student VALUES (1,'張一',12,'ssss'),(2,'張二',12,'ssss'),(3,'張三',12,'ssss'),(4,'張四',12,'ssss'),(5,'張五',12,'ssss');
複製代碼
準備工做完成,創建表,並插入5條數據。併發
模擬死鎖第一步
新建一個數據庫鏈接並執行:高併發
###事務A
begin;
select * from student where id in (1,2) lock in share mode;
複製代碼
步驟一 事務A 獲得了id 爲1,2的S鎖。
再新建一個數據庫鏈接並執行:ui
###事務B
begin;
select * from student where id in (1,3) lock in share mode;
複製代碼
步驟二 這時事務B 獲得了id爲1,3的S鎖
而後咱們在事務B 中嘗試
獲取數據id = 2 的X鎖spa
事務B
update student set age =100 where id = 2
複製代碼
步驟三, 因爲id爲2 被事務A加了S鎖,因此事務B 被阻塞。
最後咱們在事務A中嘗試獲取數據id = 3 的X鎖rest
事務A
update student set age =100 where id = 3
#執行結果:1213 - Deadlock found when trying to get lock; try restarting transaction, Time: 0.005000s
複製代碼
步驟四,因爲id爲3 被事務B加了S鎖,因此事務A被阻塞。 固然其實執行的時候被跳出死鎖警告。事務A回滾撤銷了。
code
到此,咱們模擬了整個死鎖過程,因爲B 爲了得到X鎖須要等A執行完成,而A後續反而爲了得到X鎖須要等B執行完成。因此形成了死鎖。事務
從上面的例子中咱們能夠看到死鎖的緣由是相互尋求各自手上的資源(即鎖)致使的。
可是其中有個重要的特性
須要說明就是二階段鎖協議
。
二階段鎖協議很簡單:
上面例子中步驟三,B之因此會被阻塞,是由於事務A雖然讀取數據結束了,可是事務還沒結束,因此致使讀取是加的鎖沒有釋放。
也是因爲二階段鎖協議的緣由,因此咱們應該儘量避免長事務。由於`事務執行時間越長,加鎖的時間越長,發生死鎖的機率越大```
mysql 能夠設置兩種處理方式:
通常狀況下,咱們會用第一種方式。
現實場景中有哪些容易發生死鎖的場景呢?其中最多見的一個例子是減庫存了。
扣減庫存咱們通常有如下步驟
假設流程的sql語句以下
# 查詢剩餘庫存
select last_number from stock where id = 1000 lock in share mode;
#庫存足夠 --減去庫存
update stock set last_number = last_number - 1 where id = 1000;
複製代碼
那麼問題是:
問題答案下篇文章回答。有收穫,請關注下吧。