Mysql?for?update導(dǎo)致大量行鎖的問(wèn)題
一、引言
最近同事的復(fù)盤(pán)會(huì)上提到自己for update一個(gè)不存在的where條件導(dǎo)致表鎖,然后產(chǎn)生大量的事務(wù)失敗和讀寫(xiě)超時(shí),這時(shí)博主非常奇怪,因?yàn)殡m然網(wǎng)上許多博客寫(xiě)Innodb的表鎖行鎖與鎖升級(jí),但是事實(shí)上這都是錯(cuò)誤的觀點(diǎn)。
二、分析
首先博主的環(huán)境是Mysql5.7,隔離級(jí)別是RC
博主為什么說(shuō)這些都是錯(cuò)誤的觀點(diǎn)呢?
因?yàn)樵凇陡咝阅躆ysql》和《Innodb存儲(chǔ)引擎當(dāng)中》,非常明確的提出:
1、Innodb不存在鎖升級(jí)
所以不存在因?yàn)殒i的數(shù)據(jù)量大或者多表,導(dǎo)致行鎖升級(jí)成表鎖。

2、當(dāng)for update一個(gè)不存在的where條件時(shí)
Innodb加的是Record級(jí)別鎖
這一點(diǎn)可以通過(guò)驗(yàn)證得到
- 不存在的where:
set autocommit = 0 ;
begin;
select * from t_aac_battery_compensate ?where gmt_create ?in ('2020-05-21 07:02:37') for update ;- 存在的where:
begin;
select * from t_aac_***??where gmt_create ?in ('2020-05-21 07:32:37') for update ;然后執(zhí)行
select * from information_schema.INNODB_LOCKS il?
可以看到鎖

可以看到兩個(gè)事務(wù)加的都是行級(jí)別鎖。
可能有的同學(xué)會(huì)對(duì)鎖住的行數(shù)量和數(shù)據(jù)有疑惑,這里博主發(fā)現(xiàn)這兩個(gè)數(shù)值統(tǒng)計(jì)的方式是不準(zhǔn)的,包括在《Innodb存儲(chǔ)引擎》作者明確提出lock_data是不準(zhǔn)確的。
也有的同學(xué)疑惑他加行鎖為什么會(huì)阻塞其他讀寫(xiě),這里是innodb加了行鎖之后最后一起釋放,雖然不知道它這樣的設(shè)計(jì)是出于什么考慮。
3、Innodb如果在索引中找不到記錄
會(huì)在行數(shù)據(jù)進(jìn)行搜索,鎖住主鍵,而不是鎖表

所以一些博客說(shuō)根據(jù)索引加不到鎖,innodb就會(huì)鎖全表,這是錯(cuò)誤的理解
只是可能在一些情況下他搜索行數(shù)據(jù)對(duì)主鍵加鎖的數(shù)量過(guò)多,之前也說(shuō)了innodb加行鎖是最后一起釋放的,所以阻塞了其他讀寫(xiě)
4、Innodb加鎖的方式是從上到下的
自動(dòng)加鎖只有表級(jí)別的意向鎖和行級(jí)鎖,表級(jí)別的意向鎖只會(huì)阻塞全表掃描

5、RR級(jí)別加鎖情況
上文都是基于博主線上環(huán)境配置,如果是RR隔離級(jí)別,還會(huì)有GapLock與行鎖進(jìn)行Next_keyLock算法加鎖,其實(shí)簡(jiǎn)單說(shuō)就是鎖住當(dāng)前B+樹(shù)種當(dāng)前索引到上一個(gè)索引之間(或當(dāng)前行到上一行)的間隔,防止在這個(gè)過(guò)程中有插入數(shù)據(jù),也就是防止幻讀。

但是這個(gè)情況不是絕對(duì)的,對(duì)于唯一索引,innodb會(huì)降低級(jí)別行級(jí)鎖,不會(huì)鎖住范圍

三、總結(jié)
通過(guò)以上分析得到結(jié)論:
1、RC級(jí)別下innodb都是行級(jí)鎖,表級(jí)的意向鎖只會(huì)阻塞全表掃描
2、innodb不存在鎖升級(jí)
3、innodb加不到索引會(huì)搜索行,對(duì)主鍵加鎖
4、當(dāng)for update一個(gè)不存在的where條件時(shí),Innodb加的是Record級(jí)別鎖
以上分析除了實(shí)際操作驗(yàn)證和權(quán)威書(shū)籍理解之外,博主與DBA也經(jīng)過(guò)深入探討,如果有異議歡迎討論。 另外希望各位同學(xué),多實(shí)際操作、多看權(quán)威書(shū)籍和源碼,對(duì)于網(wǎng)上的博客看一半信一半,要有自己的判斷,書(shū)籍和源碼的查看也要結(jié)合實(shí)際經(jīng)驗(yàn),因?yàn)槊總€(gè)人的腦回路是不一樣的,一不小心理解方向就可能歪了。
好了,這些僅為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- MySQL for update鎖表還是鎖行校驗(yàn)(過(guò)程詳解)
- MySQL中select...for update鎖表
- mysql中的limit 1 for update的鎖類(lèi)型
- mysql行鎖(for update)解決高并發(fā)問(wèn)題
- Mysql中的select ...for update
- Mysql查詢時(shí)如何使用for update行鎖還是表鎖
- 解讀mysql的for update用法
- MySQL SELECT?...for?update的具體使用
- mysql事務(wù)select for update及數(shù)據(jù)的一致性處理講解
- MySQL中FOR UPDATE的具體用法
相關(guān)文章
Navicat連接虛擬機(jī)mysql常見(jiàn)錯(cuò)誤問(wèn)題及解決方法
這篇文章主要介紹了Navicat連接虛擬機(jī)mysql常見(jiàn)錯(cuò)誤問(wèn)題及解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11
MySQL數(shù)據(jù)導(dǎo)入導(dǎo)出的三種辦法總結(jié)
當(dāng)我們需要切換數(shù)據(jù)庫(kù)或備份數(shù)據(jù)時(shí),導(dǎo)入和導(dǎo)出數(shù)據(jù)庫(kù)是一個(gè)常見(jiàn)的操作,下面這篇文章主要給大家介紹了關(guān)于MySQL數(shù)據(jù)導(dǎo)入導(dǎo)出的三種辦法,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05
使用MySQL的LAST_INSERT_ID來(lái)確定各分表的唯一ID值
MySQL數(shù)據(jù)表結(jié)構(gòu)中,一般情況下,都會(huì)定義一個(gè)具有‘AUTO_INCREMENT’擴(kuò)展屬性的‘ID’字段,以確保數(shù)據(jù)表的每一條記錄都可以用這個(gè)ID唯一確定2011-08-08
Mysql解決數(shù)據(jù)庫(kù)N+1查詢問(wèn)題
解析mysql中的auto_increment的問(wèn)題
簡(jiǎn)析mysql字符集導(dǎo)致恢復(fù)數(shù)據(jù)庫(kù)報(bào)錯(cuò)問(wèn)題
從源碼到實(shí)戰(zhàn)盤(pán)點(diǎn)MySQL中不寫(xiě)B(tài)inlog的N種場(chǎng)景

