新聞中心
?背景
看到許多寫select for update是行鎖還是表鎖的文章,但每篇文章的結(jié)論好像都不太一樣。同時,是行鎖還是表鎖的問題直接影響著系統(tǒng)的性能,所以特意為大家調(diào)研一番,也就有了本篇文章,一共為大家匯總驗證了20個場景下的結(jié)論。

創(chuàng)新互聯(lián)專注于企業(yè)成都營銷網(wǎng)站建設(shè)、網(wǎng)站重做改版、雙江網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、H5建站、商城系統(tǒng)網(wǎng)站開發(fā)、集團公司官網(wǎng)建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為雙江等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。
對于軟件或框架來說,特別是在有大版本更新的情況下,脫離了具體版本的結(jié)論往往是無意義的。針對這個問題,網(wǎng)絡(luò)上之所以有多個版本的答案,最主要的原因就是脫離MySQL的版本以及事務(wù)隔離級別。
本文就基于兩個MySQL版本(5.7.x、8.0.x)、兩種常見事務(wù)隔離級別(讀已提交、可重復(fù)讀)來逐一驗證??偣灿兴拇箢惽闆r,20個小場景。最后,再給大家匯總一個結(jié)論性的驗證結(jié)果。大家可以收藏,已備用到時查閱對照。
通過閱讀本文,你不僅能能夠?qū)W到相關(guān)的結(jié)論,同時也提供了一套科學(xué)的實驗方法論,個人覺得后者對大家來說更為重要。
環(huán)境準備
在驗證之前,我們先準備好具體的環(huán)境和數(shù)據(jù)。
建表語句:
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_no` varchar(16) DEFAULT NULL COMMENT '用戶編號',
`user_name` varchar(16) DEFAULT NULL COMMENT '用戶名',
`age` int(3) DEFAULT NULL COMMENT '年齡',
`address` varchar(128) DEFAULT NULL COMMENT '地址',
PRIMARY KEY (`id`),
UNIQUE KEY `un_idx_user_no` (`user_no`),
KEY `idx_user_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
初始化數(shù)據(jù):
insert into user values(null,'0001','user01',18,'北京');
insert into user values(null,'0002','user02',19,'上海');
insert into user values(null,'0003','user03',20,'廣州');
insert into user values(null,'0004','user04',21,'深圳');
insert into user values(null,'0005','user05',22,'杭州');
數(shù)據(jù)庫版本:
版本一:
>select @@version;
5.7.22
版本二:
>select @@version;
8.0.18
查詢數(shù)據(jù)事務(wù)隔離級別:
>select @@transaction_isolation;
REPEATABLE-READ
MySQL innodb支持的四種事務(wù)隔離級別:
- READ_UNCOMMITTED:讀未提交;
- READ_COMMITTED:讀已提交,后文簡稱為RC;
- REPEATABLE_READ:可重復(fù)讀,MySQL默認的事務(wù)隔離級別。后文簡稱為RR;
- SERIALIZABLE:串行讀;
設(shè)置全局隔離級別:
set global transaction isolation level REPEATABLE READ;
set global transaction isolation level READ COMMITTED;
設(shè)置會話隔離級別:
set session transaction isolation level REPEATABLE READ;
set session transaction isolation level READ COMMITTED;
關(guān)閉自動提交:
> set @@autocommit=0; //設(shè)置自動提交關(guān)閉
在執(zhí)行完鎖語句之后,可執(zhí)行commit命令進行事務(wù)提交。
commit;
準備完以上數(shù)據(jù),便可以開始每一個場景的驗證了。每個場景都起了一個編號,比如:V5.x-RR-主鍵,表示在MySQL 5.7.x,事務(wù)隔離級別為RR(可重復(fù)讀),條件字段為主鍵的場景下進行的實驗。
場景1.1:V5.x-RR-主鍵
操作:使用主鍵ID作為條件查詢,然后新開啟一個事務(wù)去更新數(shù)據(jù)。
分析思路:一,如果更新數(shù)據(jù)被阻塞,則說明加鎖成功;二,如果更新其他數(shù)據(jù)成功,則說明是行鎖,如果更新其他數(shù)據(jù)失敗則說明是表鎖。三,部分場景會測試插入操作;后續(xù)所有操作基本雷同。
執(zhí)行悲觀鎖查詢:
select * from user where id = 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
在此場景下,來看一下數(shù)據(jù)庫加的什么鎖。
當?shù)诙l語句被阻塞時,執(zhí)行查看鎖信息語句:
SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
注意,必須是正在執(zhí)行第二條語句,且第二條語句處于阻塞狀態(tài)下,上述語句才能查詢到數(shù)據(jù)。
查詢結(jié)果如下:
鎖信息
第二條記錄為for update鎖表語句,第一條記錄為單純的update語句??梢钥闯?,此場景下,lock_mode為X,lock_type為RECORD,lock_data為1。
lock_mode為X(排他鎖):即寫鎖,允許獲得排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖。
lock_type為RECORD,說是是行級鎖,lock_data表示鎖定了1條記錄。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為主鍵時,select for update為行級鎖。
當我們執(zhí)行完一個場景之后,我們需要執(zhí)行commit命令將當前事物提交。
場景1.2:V5.x-RR-唯一索引
執(zhí)行悲觀鎖操作:
select * from user where user_no = '0001' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息,同場景一的主鍵一致。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為唯一索引時,select for update為行級鎖。
場景1.3:V5.x-RR-普通索引
執(zhí)行悲觀鎖操作:
select * from user where user_name = 'user01' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息:
鎖信息
此時,鎖類型不僅僅是X排他鎖,同時還添加了GAP(間隙鎖),也就是說針對數(shù)據(jù)添加了排他間隙鎖。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
此時再進行一筆插入操作:
insert into user values(null,'0006','user05',23,'重慶');
執(zhí)行成功。
由于存在了間隙鎖,再執(zhí)行一筆user_name與查詢條件相同的插入操作:
insert into user values(null,'0008','user01',24,'成都');
執(zhí)行阻塞,說明此時有排他間隙鎖的存在。
結(jié)論:當查詢條件為普通索引時,select for update為行級鎖,同時會有排他間隙鎖存在,當插入數(shù)據(jù)滿足鎖語句查詢條件(相等、范圍等)時,會發(fā)生阻塞。
場景1.4:V5.x-RR-無索引
執(zhí)行悲觀鎖操作:
select * from user where address = '北京' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行被阻塞。
此時查詢鎖表信息展示如下:
鎖信息
這里比較奇怪是lock_type,很明顯,上述鎖操作已經(jīng)鎖住了整張表,但lock_type依舊為RECORD。出處暫時有些費解。
結(jié)論:當查詢條件無索引時,select for update為表級鎖。
場景1.5:V5.x-RR-索引-范圍查詢
執(zhí)行悲觀鎖操作:
select * from user where id > 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
執(zhí)行成功,說明并沒有鎖定id為1的記錄。
執(zhí)行插入操作:
insert into user values(null,'0007','user07',24,'武漢');
插入操作被阻塞。這是因為插入的數(shù)據(jù)生成的id滿足大于1的條件,會被阻塞。
所信息如下:
鎖信息
此時,lock_type雖然是RECORD,但是lock_data顯示supremum pseudo-record ,這就是InnoDB為了解決幻讀問題的臨鍵鎖(Next-key Lock),這里間隙鎖和臨鍵鎖可以看做是一樣的。
需要注意的是:supremum pseudo-record有可能是間隙鎖,需要結(jié)合死鎖日志里的heap no判斷。heap no 1是間隙鎖。
結(jié)論:當查詢條件有索引且查詢條件為范圍時,select for update會采用間隙鎖或臨鍵鎖,對指定范圍內(nèi)的數(shù)據(jù)進行加鎖。當然,當查詢條件無索引時,與場景1.4一致,為表鎖。
場景2.1:V8.x-RR-主鍵
執(zhí)行悲觀鎖查詢:
select * from user where id = 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查看數(shù)據(jù)庫對應(yīng)的鎖:
SELECT * FROM performance_schema.data_locks;
注意,在MySQL 8中,采用了performance_schema替代了MySQL5中基于INFORMATION_SCHEMA的鎖查詢方式。
鎖信息
上述查詢結(jié)果中,有兩條記錄。lock_type字段展示鎖范圍,lock_mode字段展示了鎖的類型。可以看到,該SQL語句先是在表范圍上加了一把IX(意向排他鎖,表鎖)。然后,在記錄(Record)范圍上添加了一把X(排他鎖),一把REC_NOT_GAP(行鎖),綜合起來就是對這條記錄添加了行級排他鎖,其他事務(wù)不能夠再對其添加任何鎖了。
這里,既然在表的層面上添加了IX(意向排他鎖),為什么不是表鎖呢?這是因為意向排他鎖的作用僅僅表名意向的鎖,當其他事務(wù)要對全表的數(shù)據(jù)進行加鎖時,那么就不需要判斷每一條數(shù)據(jù)是否被加鎖了。
事務(wù)在給一行記錄加排他鎖前,必須先取得該表的IX鎖,意向排他鎖之間相互兼容,可以并行,不會產(chǎn)生沖突。意向排他鎖存在的意義是為了更高效的獲取表鎖,主要目的是顯示事務(wù)正在鎖定某行或者試圖鎖定某行。
繼續(xù)實驗,執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為主鍵時,select for update為行級鎖。
場景2.2:V8.x-RR-唯一索引
執(zhí)行悲觀鎖操作:
select * from user where user_no = '0001' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息:
鎖信息
此時,可以看到三把鎖,一把表級別的IX鎖,一把基于唯一索引的行級排他鎖,一把基于主鍵的行級排他鎖。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為唯一索引時,select for update為行級鎖。
場景2.3:V8.x-RR-普通索引
執(zhí)行悲觀鎖操作:
select * from user where user_name = 'user01' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息:
鎖信息
此時,可以看到四把鎖,一把表級別的IX鎖,一把基于普通索引的X排他鎖,一把基于主鍵的行級排他鎖,一把基于普通索引的X,GAP排他間隙鎖。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功,說明更新操作沒有影響。
既然有排他間隙鎖,此時需再測試一筆插入操作:
insert into user values(null,'0006','user05',23,'重慶');
執(zhí)行成功。
再執(zhí)行一筆插入操作:
insert into user values(null,'0007','user01',24,'武漢');
注意這里插入的記錄user_name與鎖查詢條件相同,發(fā)現(xiàn)操作被阻塞。
通過兩筆插入操作可以看出,排他間隙鎖會阻塞符合查詢條件(user_name='user01')的數(shù)據(jù)的插入。
結(jié)論:當查詢條件為普通索引時,select for update為行級鎖,同時會多一把排他間隙鎖,如果插入數(shù)據(jù)滿足鎖語句的查詢條件(等于、范圍條件等),則無法插入。
場景2.4:V8.x-RR-無索引
執(zhí)行悲觀鎖操作:
select * from user where address = '北京' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息:
鎖信息
此時,數(shù)據(jù)庫一共加了8把鎖,一把表級別的IX意向排他鎖,6把基于主鍵的針對數(shù)據(jù)記錄(總共6條)的X鎖,一把針對記錄的supremum pseudo-record鎖。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行被阻塞。
結(jié)論:當查詢條件無索引時,select for update為表級鎖。
場景2.5:V8.x-RR-索引-范圍查詢
執(zhí)行悲觀鎖操作:
select * from user where id > 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
執(zhí)行成功,說明并沒有鎖定id為1的記錄。
執(zhí)行插入操作:
insert into user values(null,'0007','user07',24,'武漢');
插入操作被阻塞。這是因為插入的數(shù)據(jù)生成的id滿足大于1的條件,會被阻塞。
查詢鎖信息如下:
鎖信息
此時,鎖信息對比場景2.4,少了一條不滿足條件記錄(id=1)的鎖,其他符合條件的數(shù)據(jù)均被鎖。
結(jié)論:當查詢條件有索引且查詢條件為范圍時,select for update會采用間隙鎖或臨鍵鎖,對指定范圍內(nèi)的數(shù)據(jù)進行加鎖。
完成了上面針對RR事務(wù)隔離級別的驗證,下面將數(shù)據(jù)庫事務(wù)隔離級別切換為RC。
set global transaction isolation level READ COMMITTED;
注意,此處可能需要重啟數(shù)據(jù)庫,如果通過命令配置無效,可通過數(shù)據(jù)庫配置文件進行配置,重啟。
另外,也可以通過在所有命令窗口執(zhí)行session級別的設(shè)置,也可以達到效果,設(shè)置完成之后注意需要進行驗證。
場景3.1:V5.x-RC-主鍵
執(zhí)行悲觀鎖查詢:
select * from user where id = 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
鎖信息與RR事務(wù)相同。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為主鍵時,select for update為行級鎖。
場景3.2:V5.x-RC-唯一索引
執(zhí)行悲觀鎖操作:
select * from user where user_no = '0001' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息,與RR一致。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為唯一索引時,select for update為行級鎖。
場景3.3:V5.x-RC-普通索引
執(zhí)行悲觀鎖操作:
select * from user where user_name = 'user01' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息如下:
鎖信息
再把RR場景下的鎖信息貼出來:
鎖信息
可以看出,RC事務(wù)隔離級別時比RR事務(wù)隔離級別時少了一個GAP(間隙鎖)。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
此時再進行一筆插入操作:
insert into user values(null,'0009','user01',24,'鄭州');
執(zhí)行成功。
再驗證下間隙鎖是否真的不存在,執(zhí)行一筆user_name與查詢條件相同的插入操作:
insert into user values(null,'0008','user01',24,'成都');
執(zhí)行成功,說明此時間隙鎖的不存在了。
結(jié)論:當查詢條件為普通索引時,select for update為行級鎖,無間隙鎖。
場景3.4:V5.x-RC-無索引
執(zhí)行悲觀鎖操作:
select * from user where address = '北京' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
鎖信息如下:
鎖信息
顯示基于主鍵的排他鎖,這塊挺出乎意料的,并沒有進行表鎖。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
再執(zhí)行一筆插入操作,插入數(shù)據(jù)與查詢條件address一致:
insert into user values(null,'0011','user01',24,'北京');
執(zhí)行成功。
結(jié)論:當查詢條件無索引時,select for update為行級鎖,也就說,在RC事務(wù)隔離級別下,即便無索引,也是只鎖記錄,與通常的直知覺不同。
原因:會出現(xiàn)上述情況的原因是,本來如果鎖條件上沒有索引,MySQL會走聚簇(主鍵)索引進行全表掃描過濾,每條記錄都會添加上X鎖。但為了效率,MySQL會對掃描過程中不滿足條件的記錄進行解鎖操作。
場景3.5:V5.x-RC-索引-范圍查詢
執(zhí)行悲觀鎖操作:
select * from user where id > 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
執(zhí)行成功,說明并沒有鎖定id為1的記錄。
執(zhí)行更新操作:
update user set age = age +1 where id = 2;
操作被阻塞。這是因為操作的數(shù)據(jù)的id滿足大于1的條件,會被阻塞。
所信息如下:
鎖信息
結(jié)論:當查詢條件有索引且查詢條件為范圍時,select for update對指定范圍內(nèi)的數(shù)據(jù)進行加鎖。
場景4.1:V8.x-RC-主鍵
執(zhí)行悲觀鎖查詢:
select * from user where id = 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
鎖信息同RR。
繼續(xù)實驗,執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為主鍵時,select for update為行級鎖。
場景4.2:V8.x-RC-唯一索引
執(zhí)行悲觀鎖操作:
select * from user where user_no = '0001' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
鎖信息同RR。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件為唯一索引時,select for update為行級鎖。
場景4.3:V8.x-RC-普通索引
執(zhí)行悲觀鎖操作:
select * from user where user_name = 'user01' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息:
鎖信息
對照一下RR場景下的鎖信息:
鎖信息
可以看出RC場景下筆RR場景下少了一條行級間隙鎖。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功,說明更新操作沒有影響。
驗證一下是否有排他間隙鎖,此時需再測試一筆插入操作:
insert into user values(null,'0010','user05',23,'重慶');
執(zhí)行成功。
再執(zhí)行一筆插入操作:
insert into user values(null,'0007','user01',24,'武漢');
注意這里插入的記錄user_name與鎖查詢條件相同,執(zhí)行成功,說明真的不存在X,GAP(排他間隙鎖)。
結(jié)論:當查詢條件為普通索引時,select for update為行級鎖。
場景4.4:V8.x-RC-無索引
執(zhí)行悲觀鎖操作:
select * from user where address = '北京' for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
此處更新操作被阻塞,說明數(shù)據(jù)鎖定成功。
查詢鎖信息:
鎖信息
對照一下RR場景:
鎖信息
對于RR場景,RC場景下,只有一條排他行鎖(X,REC_NOT_GAP)。
執(zhí)行更新其他記錄操作:
update user set age = age +1 where id = 2;
執(zhí)行成功。
結(jié)論:當查詢條件無索引時,select for update為行級鎖。這里的原因與場景3.4一致。
場景4.5:V8.x-RC-索引-范圍查詢
執(zhí)行悲觀鎖操作:
select * from user where id > 1 for update;
執(zhí)行更新操作:
update user set age = age +1 where id = 1;
執(zhí)行成功,說明并沒有鎖定id為1的記錄。
執(zhí)行插入操作:
insert into user values(null,'0012','user12',24,'--');
執(zhí)行成功。
查詢鎖信息如下:
鎖信息
對照RR場景下的鎖信息:
鎖信息
此時,RC場景下,少了臨鍵鎖,排他鎖也變?yōu)榱诵屑壟潘i。
結(jié)論:當查詢條件有索引且查詢條件為范圍時,select for update會對指定范圍內(nèi)的數(shù)據(jù)進行加鎖,只會阻塞符合條件的記錄,不影響插入操作。
場景及結(jié)論
完成了上面的實驗之后,我們通過一個表格來總結(jié)一下所有的場景和結(jié)論。
|
版本 |
主鍵 |
唯一索引 |
普通索引 |
無索引 |
范圍查詢 |
|
MySQL 5.7.x - RR |
X:行鎖 |
X,行鎖 |
X,GAP:行鎖,間隙鎖,條件范圍內(nèi)會阻塞 |
表鎖 |
指定范圍加鎖,insert阻塞 |
|
MySQL 8.0.x - RR |
X,REC_NOT_GAP:行級排他鎖 |
X,REC_NOT_GAP:行級排他鎖 |
X;X,REC_NOT_GAP;X,GAP:行鎖+排他間隙鎖,阻塞范圍內(nèi)insert; |
表鎖,每條記錄一個X鎖 |
指定范圍加鎖,insert阻塞 |
|
MySQL 5.7.x - RC |
X:行鎖 |
X,行鎖 |
X,行鎖,無間隙鎖; |
行鎖 |
指定范圍加鎖,更新、insert阻塞 |
|
MySQL 8.0.x - RC |
X,REC_NOT_GAP:行級排他鎖 |
X,REC_NOT_GAP:行級排他鎖 |
X,REC_NOT_GAP:行鎖,無間隙鎖; |
X,REC_NOT_GAP:行鎖 |
指定范圍加鎖,不阻塞insert |
從上面表中我們可以總結(jié)出以下結(jié)論(基于RR、RC兩種事務(wù)隔離級別):
- 無論哪個版本的MySQL,查詢條件為主鍵、唯一索引、普通索引的情況下,為行鎖;
- 查詢條件為普通索引時,事務(wù)隔離級別為RR時,MySQL還會添加一個間隙鎖,條件內(nèi)的插入、更新會被阻塞;
- 事務(wù)隔離級別為RR時,查詢條件無索引,為表鎖;
- 事務(wù)隔離級別為RC時,查詢條件無索引,為行鎖;
- 查詢條件為范圍時,有索引的情況下,除MySQL 8.0.x RC場景下不阻塞插入操作,其他場景均阻塞指定范圍更新、插入操作;
通過上面的結(jié)論,我們可以看出,并不是簡單的說“有索引就是行鎖,無索引就是表鎖”,因為在事務(wù)隔離級別為RC時,無索引,同樣表現(xiàn)(被優(yōu)化)為行鎖。
至于,根據(jù)范圍條件(大于、小于、不等于、between、like等)查詢、查詢無結(jié)果等情況,大家可根據(jù)上述實驗方法進行自行驗證。
本文為大家提供了實驗方法,并針對常見的場景給出了結(jié)論,希望能夠幫到你,也希望大家能夠點贊、轉(zhuǎn)發(fā)、收藏,以備不時之需。
新聞標題:selectforupdate行鎖or表鎖,20個場景分析,還真得看情況
本文路徑:http://fisionsoft.com.cn/article/djsesep.html


咨詢
建站咨詢
