通過好多個深夜艱難的單步調(diào)試,終于找到了一個理想的斷點,可以看到大部分獲取鎖的過程
代碼在lock0lock.c
的static enum db_err lock_rec_lock()
函數(shù)中,這個函數(shù)會顯示,獲取鎖的過程,以及獲取鎖成功與否。
場景1:通過主鍵進行刪除
表結(jié)構(gòu)
CREATE TABLE `t1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
delete from t1 where id = 10;
![](http://img.jbzj.com/file_images/article/201905/2019522142940885.jpg?201942214332)
可以看到,對索引 PRIMARY 加鎖,mode = 1027,1027是什么意思呢?1027 = LOCK_REC_NOT_GAP + LOCK_X(非 gap 的記錄鎖且是 X 鎖)
過程如下
![](http://img.jbzj.com/file_images/article/201905/2019522142945888.jpg?2019422143245)
結(jié)論:根據(jù)主鍵 id 去刪除數(shù)據(jù),且沒有其它索引的情況下,此 SQL 只需要在 id = 10 這條記錄上對主鍵索引加 X 鎖即可
場景2:通過唯一索引進行刪除
表結(jié)構(gòu)做了微調(diào),增加了 name 的唯一索引
構(gòu)造數(shù)據(jù)
CREATE TABLE `t2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_name` (`name`)
) ;
INSERT INTO `t2` (`id`, `name`) VALUES
(1,'M'),
(2,'Y'),
(3,'S'),
(4,'Q'),
(5,'L');
測試sql語句
delete from t2 where name = "Y"
來看實際源碼調(diào)試的結(jié)果
第一步:
![](http://img.jbzj.com/file_images/article/201905/2019522142950034.jpg?2019422143233)
第二步:
![](http://img.jbzj.com/file_images/article/201905/2019522142955065.jpg?2019422143222)
結(jié)論:這個過程是先對唯一鍵 uk_name 加 X 鎖,然后再對聚簇索引(主鍵索引)加 X 鎖
過程如下
![](http://img.jbzj.com/file_images/article/201905/2019522143000170.jpg?201942214329)
場景3:通過普通索引進行刪除
構(gòu)造數(shù)據(jù)
CREATE TABLE `t3` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `idx_name` (`name`)
);
INSERT INTO `t3` (`id`, `name`) VALUES
(1,'N'),
(2,'G'),
(3,'I'),
(4,'N'),
(5,'X');
測試語句:
delete from t3 where name = "N";
調(diào)試過程如圖:
![](http://img.jbzj.com/file_images/article/201905/2019522143004879.jpg?2019422143154)
結(jié)論:通過普通索引進行更新時,會對滿足條件的所有普通索引加 X 鎖,同時會對相關(guān)的主鍵索引加 X 鎖
過程如下
![](http://img.jbzj.com/file_images/article/201905/2019522143009542.jpg?2019422143142)
場景4:不走索引進行刪除
CREATE TABLE `t4` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
)
INSERT INTO `t4` (`id`, `name`) VALUES
(1,'M'),
(2,'Y'),
(3,'S'),
(4,'Q'),
(5,'L');
delete from t4 where name = "S";
![](http://img.jbzj.com/file_images/article/201905/2019522143014679.jpg?2019422143128)
![](http://img.jbzj.com/file_images/article/201905/2019522143019633.jpg?2019422143116)
總共有 5 把 X 鎖,剩下的 3 把就不一一放上來了
結(jié)論:不走索引進行更新時,sql 會走聚簇索引(主鍵索引)對全表進行掃描,因此每條記錄,無論是否滿足條件,都會被加上X鎖。還沒完...
但是為了效率考量,MySQL做了優(yōu)化,對于不滿足條件的記錄,會在判斷后放鎖,最終持有的,是滿足條件的記錄上的鎖,但是不滿足條件的記錄上的加鎖/放鎖動作不會省略。
過程如下
![](http://img.jbzj.com/file_images/article/201905/2019522143023160.jpg?201942214311)
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:- MySQL死鎖問題分析及解決方法實例詳解
- Mysql使用kill命令解決死鎖問題(殺死某條正在執(zhí)行的sql語句)
- MySQL redo死鎖問題排查及解決過程分析
- MySQL數(shù)據(jù)庫之Purge死鎖問題解析
- 關(guān)于MySQL死鎖問題的深入分析