MySQL?事務(wù)隔離性及鎖處理方式
一、事務(wù)隔離性概述
事務(wù)隔離性(Isolation) 是指多個(gè)并發(fā)事務(wù)之間相互隔離,一個(gè)事務(wù)的執(zhí)行不應(yīng)該影響其他事務(wù)的執(zhí)行。
MySQL 支持四種事務(wù)隔離級(jí)別,默認(rèn)隔離級(jí)別:可重復(fù)讀(Repeatable Read)。

鎖的行為與事務(wù)的隔離級(jí)別緊密相關(guān):
讀未提交:通常不加鎖,通過直接讀最新數(shù)據(jù)實(shí)現(xiàn),存在臟讀、幻讀等問題。
讀已提交:每次讀取的都是已提交的最新數(shù)據(jù)(快照)。 對(duì)于 UPDATE、DELETE,只對(duì)實(shí)際修改的行加鎖(記錄鎖),不使用間隙鎖,所無法避免幻讀。
可重復(fù)讀(InnoDB 的默認(rèn)級(jí)別):在事務(wù)開始時(shí)創(chuàng)建一致性視圖,整個(gè)事務(wù)期間都讀取這個(gè)視圖。使用臨鍵鎖作為默認(rèn)的行鎖算法,通過鎖住記錄和間隙來防止幻讀。
串行化:最高的隔離級(jí)別,通過強(qiáng)制事務(wù)串行執(zhí)行來避免所有并發(fā)問題。 在這個(gè)級(jí)別下,InnoDB 可能會(huì)隱式地將普通的 SELECT 語句轉(zhuǎn)換為 SELECT ... FORSHARE,從而加共享鎖,導(dǎo)致讀讀也可能阻塞。
二、MySQL 保證隔離性的機(jī)制
MySQL 的鎖機(jī)制是為了在并發(fā)訪問下,保證數(shù)據(jù)的一致性、完整性而設(shè)計(jì)的。它可以大致分為以下三個(gè)維度來理解:
- 鎖的粒度:鎖定的范圍大小
- 鎖的模式:鎖的兼容性,即多個(gè)鎖之間能否共存
- 鎖的類型:從程序員視角看,鎖的共享與排他特性
按鎖的粒度劃分
1 全局鎖,作用范圍:整個(gè)數(shù)據(jù)庫實(shí)例。
FLUSH TABLES WITH READ LOCK; SET read_only = ON
效果:使數(shù)據(jù)庫處于只讀狀態(tài),所有數(shù)據(jù)修改操作(DML)和數(shù)據(jù)結(jié)構(gòu)變更操作 (DDL)都會(huì)被阻塞。
使用場(chǎng)景:全庫邏輯備份。但請(qǐng)注意,在 InnoDB 中,由于有 MVCC,通常使 用 mysqldump --single-transaction 來進(jìn)行不鎖表的熱備份,這比全局鎖更好。
2 表級(jí)鎖,作用范圍:整張表
LOCK TABLES table_name READ/WRITE; 和 UNLOCK TABLES;
MyISAM 引擎默認(rèn)使用表鎖。
元數(shù)據(jù)鎖:不需要顯式使用,在執(zhí)行 DML(如 SELECT, INSERT, UPDATE, DELETE)時(shí)自動(dòng)加,防止表結(jié)構(gòu)被修改。讀鎖之間不互斥,但寫鎖是排他的。
意向鎖:InnoDB 特有的表級(jí)鎖,用于快速判斷表內(nèi)是否有行鎖沖突。
效果:鎖定整張表,粒度大,并發(fā)性能差。
3 行級(jí)鎖, 作用范圍:?jiǎn)涡谢蚨嘈杏涗?/h4>
支持引擎:InnoDB。
效果:粒度最小,只鎖定需要操作的行,極大提高了并發(fā)性能。但管理開銷最大,容易 導(dǎo)致死鎖。
實(shí)現(xiàn)方式:InnoDB 通過給索引項(xiàng)加鎖來實(shí)現(xiàn)行鎖。這意味著:如果查詢條件沒有用到索引,InnoDB 會(huì)退化為表鎖,行鎖實(shí)際上是加在索引記錄上的。
InnoDB 的行鎖模式(鎖的類型)
1 共享鎖,簡(jiǎn)稱:S 鎖。
特性:又稱為讀鎖。一個(gè)事務(wù)獲取了某行的共享鎖后,其他事務(wù)也可以獲取同一行的共享鎖(讀讀兼容),但不能獲取該行的排他鎖(讀寫不兼容)。
加鎖方式:
SELECT ... LOCK IN SHARE MODE; -- 在舊版本中 SELECT ... FOR SHARE; -- 在 MySQL 8.0+ 中推薦使用
2 排他鎖,簡(jiǎn)稱:X 鎖。
特性:又稱為寫鎖。一個(gè)事務(wù)獲取了某行的排他鎖后,其他事務(wù)既不能獲取該行的共享鎖,也不能獲取該行的排他鎖(寫寫、讀寫都不兼容)。
加鎖方式:
SELECT ... FOR UPDATE;
DML 語句(UPDATE, DELETE, INSERT)會(huì)自動(dòng)給涉及的行加上排他鎖。
兼容性矩陣:

三、行鎖的算法(鎖定了哪些數(shù)據(jù))
InnoDB 的行鎖是通過對(duì)索引項(xiàng)加鎖實(shí)現(xiàn)的,根據(jù)查詢條件和索引使用情況,鎖定的范圍有所不同。
3.1 記錄鎖
鎖定:單個(gè)索引記錄。
場(chǎng)景:當(dāng)語句精確匹配到某一條記錄,且使用了唯一索引(包括主鍵)時(shí)。
示例:
SELECT * FROM users WHERE id = 10 FOR UPDATE; 如果 id 是主鍵,這條語句會(huì)在 id=10 這條索引記錄上加 X 鎖。
3.2 間隙鎖
鎖定:一個(gè)索引區(qū)間,但不包括記錄本身。例如鎖住 (5, 10) 這個(gè)開區(qū)間。
目的:防止其他事務(wù)在區(qū)間內(nèi)插入新的記錄,從而解決幻讀問題。
場(chǎng)景:使用范圍查詢或者查詢不存在的記錄時(shí)。
示例:
SELECT * FROM users WHERE id BETWEEN 5 AND 10 FOR UPDATE; 這條語句會(huì)鎖住 id 在 (5, 10) 區(qū)間內(nèi)的所有“間隙”,防止插入 id=6,7,8,9 的新記錄。
3.3 臨鍵鎖
鎖定:一個(gè)索引記錄 + 該記錄之前的間隙。它是 記錄鎖 + 間隙鎖 的組合。
目的:InnoDB 默認(rèn)的行鎖算法。它既鎖住了記錄本身,也鎖住了它之前的間隙,從在 “可重復(fù)讀”隔離級(jí)別下有效地防止了幻讀。
示例:如果表中有記錄 id=5, 10, 15。
SELECT * FROM users WHERE id > 10 AND id <= 15 FOR UPDATE; 這條語句會(huì)鎖定 (10, 15] 這個(gè)區(qū)間。它鎖住了 id=15 這條記錄(記錄鎖), 以及 (10,15) 這個(gè)間隙(間隙鎖)。
四、 死鎖
當(dāng)兩個(gè)或多個(gè)事務(wù)相互等待對(duì)方釋放鎖時(shí),就會(huì)發(fā)生死鎖。
示例:
事務(wù) A:UPDATE table SET ... WHERE id = 1; (持有 id=1 的 X 鎖)
事務(wù) B:UPDATE table SET ... WHERE id = 2; (持有 id=2 的 X 鎖)
事務(wù) A:UPDATE table SET ... WHERE id = 2; (等待事務(wù) B 釋放 id=2 的鎖)
事務(wù) B:UPDATE table SET ... WHERE id = 1; (等待事務(wù) A 釋放 id=1 的鎖)
-> 死鎖發(fā)生!
InnoDB 的處理方式:
InnoDB 有一個(gè)內(nèi)置的死鎖檢測(cè)機(jī)制,會(huì)主動(dòng)選擇一個(gè)回滾成本較小的事務(wù)(通常就是影響行數(shù)較少的事務(wù))進(jìn)行回滾,并報(bào)出 1213 錯(cuò)誤(Deadlock found when trying to get lock)。
另一個(gè)事務(wù)則可以繼續(xù)執(zhí)行。
如何避免死鎖:
盡量讓事務(wù)以相同的順序訪問表和行。
在事務(wù)中,盡量一次鎖定所有需要的資源,減少事務(wù)大小。
使用較低的隔離級(jí)別(如 Read Committed)可以減少間隙鎖的使用,從而降低死鎖概率。
為表添加合理的索引,避免全表掃描導(dǎo)致鎖表。
到此這篇關(guān)于MySQL 事務(wù)隔離性及鎖的文章就介紹到這了,更多相關(guān)mysql內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL數(shù)據(jù)庫基礎(chǔ)概念和簡(jiǎn)單使用
本文介紹了數(shù)據(jù)庫主流數(shù)據(jù)庫類型及MySQL的基本使用,包括:數(shù)據(jù)庫解決文件存儲(chǔ)的四大缺陷;MySQL的安裝連接、服務(wù)器管理及數(shù)據(jù)庫表關(guān)系;數(shù)據(jù)庫邏輯存儲(chǔ)結(jié)構(gòu);MySQL架構(gòu)的跨平臺(tái)特性;SQL語言分類(DDL、DML、DQL、DCL);存儲(chǔ)引擎的作用及對(duì)比(InnoDB、MyISAM等)2025-08-08
mysql+Spring數(shù)據(jù)庫隔離級(jí)別與性能分析
數(shù)據(jù)庫隔離級(jí)別與Spring配置事務(wù)的聯(lián)系及性能影響,以下是個(gè)人理解,如果有瑕疵請(qǐng)及時(shí)指正2014-05-05
MYSQL IN 與 EXISTS 的優(yōu)化示例介紹
當(dāng)B表的數(shù)據(jù)集必須小于A表的數(shù)據(jù)集時(shí),用in優(yōu)于exists,當(dāng)A表的數(shù)據(jù)集系小于B表的數(shù)據(jù)集時(shí),用exists優(yōu)于in2014-08-08
mysql自動(dòng)增量備份的實(shí)例方法(本地備份與遠(yuǎn)程備份)
mysql自動(dòng)增量備份的例子(本地備份與遠(yuǎn)程備份),有需要的朋友可以參考下2013-02-02
淺析mysql 共享表空間與獨(dú)享表空間以及他們之間的轉(zhuǎn)化
本篇文章是對(duì)mysql 共享表空間與獨(dú)享表空間以及他們之間的轉(zhuǎn)化進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06
Mysql之如何實(shí)現(xiàn)行列轉(zhuǎn)換
這篇文章主要介紹了Mysql之如何實(shí)現(xiàn)行列轉(zhuǎn)換問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
Linux7.6二進(jìn)制安裝Mysql8.0.27詳細(xì)操作步驟
大家好,本篇文章主要講的是Linux7.6二進(jìn)制安裝Mysql8.0.27詳細(xì)操作步驟,感興趣的同學(xué)快來看一看吧,希望對(duì)你起到幫助2021-11-11

