MySQL表鎖、行鎖、排它鎖及共享鎖的使用詳解
前言
事務(wù)隔離級(jí)別的實(shí)現(xiàn)原理:簡(jiǎn)單來(lái)說(shuō)就是各種鎖機(jī)制和MVCC多版本并發(fā)控制
我們學(xué)習(xí)知識(shí)的時(shí)候,需要了解知識(shí)點(diǎn)出現(xiàn)的原因,什么情況下能用到這個(gè)知識(shí)
我們說(shuō)到事務(wù),就得說(shuō)到事務(wù)的ACID特性,說(shuō)到隔離性的時(shí)候,事務(wù)要能夠允許并發(fā)執(zhí)行,并發(fā)執(zhí)行為了同時(shí)保證數(shù)據(jù)的安全性,一致性和并發(fā)的效率,就需要設(shè)置事務(wù)的隔離級(jí)別
一、事務(wù)隔離機(jī)制的選擇
- 如果我們完全不管,使用未提交讀的事務(wù)隔離機(jī)制,任由這些線程并發(fā)操作數(shù)據(jù)庫(kù),那就會(huì)出現(xiàn)臟讀(讀取了未commit的數(shù)據(jù))、不可重復(fù)讀(兩次查詢值不同)、幻讀(兩次查詢數(shù)據(jù)量不同)等問(wèn)題,數(shù)據(jù)的安全性最低,優(yōu)點(diǎn)是并發(fā)效率非常高,一般不會(huì)使用
- 如果我們串行化(靠鎖實(shí)現(xiàn)),通過(guò)鎖給所有的事務(wù)都排個(gè)序,雖然數(shù)據(jù)的安全性提高了,并發(fā)的效率就太低了,一般也不會(huì)使用
- 所以我們一般用的是已提交讀、可重復(fù)讀這兩個(gè)隔離級(jí)別,平衡了數(shù)據(jù)的安全性,一致性以及并發(fā)的效率 ,是由MVCC多版本并發(fā)控制實(shí)現(xiàn)的(MVCC是已提交讀和可重復(fù)讀的原理,鎖是串行化的原理)
二、表級(jí)鎖&行級(jí)鎖
表級(jí)鎖:對(duì)整張表加鎖。開銷小(因?yàn)椴挥萌フ冶淼哪骋恍械挠涗涍M(jìn)行加鎖,要修改這張表,直接申請(qǐng)加這張表的鎖),加鎖快,不會(huì)出現(xiàn)死鎖;鎖粒度大,發(fā)生鎖沖突的概率高,并發(fā)度低
行級(jí)鎖:對(duì)某行記錄加鎖。開銷大(需要找到表中相應(yīng)的記錄,有搜表搜索引的過(guò)程),加鎖慢,會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度高

InnoDB存儲(chǔ)引擎支持事務(wù)處理,表支持行級(jí)鎖定,并發(fā)能力更好
- InnoDB行鎖是通過(guò)給索引上的索引項(xiàng)加鎖來(lái)實(shí)現(xiàn)的,而不是給表的行記錄加鎖實(shí)現(xiàn)的,這就意味者只有通過(guò)索引條件檢索數(shù)據(jù),InnoDB才使用行級(jí)鎖,否則InnoDB將使用表鎖
- 由于InnoDB的行鎖實(shí)現(xiàn)是針對(duì)索引字段添加的鎖,不是針對(duì)行記錄加的鎖,因此雖然訪問(wèn)的是InnoDB引擎下表的不同行,但如果使用相同的索引字段作為過(guò)濾條件,依然會(huì)發(fā)生鎖沖突,只能串行進(jìn)行,不能并發(fā)進(jìn)行
- 即使SQL中使用了索引,但是經(jīng)過(guò)MySQL的優(yōu)化器后,如果認(rèn)為全表掃描比使用索引效率高,此時(shí)會(huì)放棄使用索引,因此也不會(huì)
使用行鎖,而是使用表鎖,比如對(duì)一些很小的表,MySQL就不會(huì)去使用索引
三、排它鎖(Exclusive)和共享鎖(Shared)
- 排它鎖,又稱為X鎖,寫鎖
- 共享鎖,又稱為S鎖,讀鎖
讀讀(SS)之間是可以兼容的,但是讀寫(SX、SX)之間,寫寫(XX)之間是互斥的
對(duì)事務(wù)加X和S鎖之間有以下的關(guān)系:
- 一個(gè)事務(wù)對(duì)數(shù)據(jù)對(duì)象A加了 S 鎖,可以對(duì)A進(jìn)行讀取操作但不能進(jìn)行update操作,加鎖期間其它事務(wù)能對(duì)A加S鎖但不能加 X 鎖
- 一個(gè)事務(wù)對(duì)數(shù)據(jù)對(duì)象A加了 X 鎖,就可以對(duì)A進(jìn)行讀取和更新,加鎖期間其它事務(wù)不能對(duì)A加任何鎖
顯示加鎖:select … lock in share mode強(qiáng)制獲取共享鎖,select … for update獲取排它鎖
1. 測(cè)試不同事務(wù)之間排它鎖和共享鎖的兼容性
我們先查看表的SQL以及內(nèi)容

查看隔離級(jí)別:

首先開啟一個(gè)事務(wù),給id=7的數(shù)據(jù)加上排它鎖

在用另一個(gè)客戶端開啟事務(wù)

我們用另一個(gè)事務(wù)的服務(wù)線程給id=7的數(shù)據(jù)加上排它鎖,阻塞了

我們嘗試給id=7的數(shù)據(jù)加上共享鎖,還是阻塞了
總結(jié):不同事務(wù)之間對(duì)于數(shù)據(jù)的鎖,只有SS鎖可以共存,XX、SX、XS都不能共存
2. 測(cè)試行鎖加在索引項(xiàng)上
其實(shí)行鎖是加在索引樹上的

用表的無(wú)索引字段作為過(guò)濾條件

事務(wù)2現(xiàn)在同樣想獲取這條記錄的排它鎖,可想而知地失敗了;那現(xiàn)在事務(wù)2獲取chenwei的記錄的排它鎖,試試能不能成功

InnoDB是支持行鎖的,剛才以主鍵id為過(guò)濾條件時(shí),事務(wù)1和事務(wù)2獲取不同行的鎖是可以成功的。然而現(xiàn)在我們發(fā)現(xiàn)獲取name為chenwei的排它鎖也獲取不到了,這是為什么?我們解釋一下:
InnoDB的行鎖是通過(guò)給索引項(xiàng)加鎖來(lái)實(shí)現(xiàn)的,而不是給表的行記錄加鎖實(shí)現(xiàn)的
而我們用name作為過(guò)濾條件沒有用到索引,自然就不會(huì)使用行鎖,而是使用表鎖。這就意味著只有通過(guò)索引檢索數(shù)據(jù),InnoDB才使用行級(jí)鎖,否則InnoDB都將使用表鎖!!!
我們給name字段加上索引


我們發(fā)現(xiàn),給name加上索引后,兩個(gè)事務(wù)可以獲取到不同行的排它鎖(for update),再一次證明了InnoDB的行鎖是加在索引項(xiàng)上的

因?yàn)楝F(xiàn)在name走的是索引, 通過(guò)zhangsan在輔助索引樹上找到它所在行記錄的id是7,然后到主鍵索引樹上,獲取對(duì)應(yīng)行記錄的排他鎖(個(gè)人猜測(cè)應(yīng)該是輔助索引樹和主鍵索引樹相應(yīng)的記錄都加了鎖)
四、串行化隔離級(jí)別測(cè)試
(所有的事務(wù)都使用排它鎖或共享鎖,不需要用戶手動(dòng)加鎖)
設(shè)置串行化隔離級(jí)別

兩個(gè)事務(wù)可以同時(shí)獲取共享鎖(SS共存)

現(xiàn)在讓事務(wù)2插入數(shù)據(jù)

此時(shí)由于insert需要加排它鎖,但由于事務(wù)1已經(jīng)對(duì)整張表添加了共享鎖,事務(wù)2無(wú)法再對(duì)表成功加鎖(SX不共存)
rollback一下

因?yàn)槲覀兘oname加上了索引,以上的select相當(dāng)于給name為zhangsan的數(shù)據(jù)加上了行共享鎖
事務(wù)2 update

事務(wù)2不能update,因?yàn)榇藭r(shí)已經(jīng)被事務(wù)1的共享鎖鎖住了整個(gè)表
事務(wù)2在輔助索引樹上找zhangsan,找到對(duì)應(yīng)的主鍵值,然后去主鍵索引樹找到相應(yīng)的記錄,但是發(fā)現(xiàn)這行記錄已經(jīng)被共享鎖鎖住了,事務(wù)2可以獲取共享鎖,但是不能獲取排他鎖

我們用主鍵索引id試試能不能update

依然阻塞住了,雖然我們where后面的字段現(xiàn)在使用的id而不是name,但是name也是通過(guò)輔助索引樹找到對(duì)應(yīng)的主鍵,再到主鍵索引樹上找相應(yīng)的記錄,而主鍵索引樹上的記錄加了鎖(個(gè)人猜想應(yīng)該是輔助索引樹和主鍵索引樹對(duì)應(yīng)的數(shù)據(jù)都加了鎖)
我們update id=8的數(shù)據(jù),成功了。因?yàn)槲覀僺elect的時(shí)候,只是給id=7的數(shù)據(jù)加上了行鎖,我們操作id=8的數(shù)據(jù)當(dāng)然可以成功

有索引,則使用行鎖;沒有索引,則使用表鎖。
表級(jí)鎖還是行級(jí)鎖說(shuō)的是鎖的粒度,共享鎖和排他鎖說(shuō)的是鎖的性質(zhì),不管是表鎖還是行鎖,都有共享鎖和排他鎖的區(qū)分
總結(jié)
到此這篇關(guān)于MySQL表鎖、行鎖、排它鎖及共享鎖使用的文章就介紹到這了,更多相關(guān)MySQL表鎖、行鎖、排它鎖和共享鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
對(duì)MySQL慢查詢?nèi)罩具M(jìn)行分析的基本教程
這篇文章主要介紹了對(duì)MySQL慢查詢?nèi)罩具M(jìn)行分析的基本教程,文中提到的Query-Digest-UI這個(gè)基于B/S的圖形化查看工具非常好用,需要的朋友可以參考下2015-12-12
如何用mysqldump進(jìn)行全量和時(shí)間點(diǎn)備份
這篇文章主要介紹了如何用mysqldump進(jìn)行全量和時(shí)間點(diǎn)備份,幫助大家更好的管理MySQL數(shù)據(jù)庫(kù),感興趣的朋友可以了解下2020-08-08
SQL語(yǔ)句多表聯(lián)查的實(shí)現(xiàn)方法示例
多表聯(lián)合檢索可以通過(guò)連接運(yùn)算來(lái)完成,而連接運(yùn)算又可以通過(guò)廣義笛卡爾積后再進(jìn),下面這篇文章主要給大家介紹了關(guān)于SQL語(yǔ)句多表聯(lián)查實(shí)現(xiàn)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04
碰到MySQL無(wú)法啟動(dòng)1067錯(cuò)誤問(wèn)題解決方法
創(chuàng)建primay key過(guò)程中發(fā)生了斷電,當(dāng)電腦再次啟動(dòng)時(shí)候,發(fā)現(xiàn)mysql 服務(wù)無(wú)法啟動(dòng),使用 net start 提示 1067錯(cuò)誤;后來(lái)只能通過(guò)手工刪除數(shù)據(jù)文件,日志文件,再啟動(dòng)服務(wù),然后導(dǎo)入數(shù)據(jù)來(lái)完成2013-01-01
MySQL利用索引優(yōu)化ORDER BY排序語(yǔ)句的方法
這篇文章主要介紹了MySQL利用索引優(yōu)化ORDER BY排序語(yǔ)句的方法,幫助大家更好的理解和使用MySQL數(shù)據(jù)庫(kù),感興趣的朋友可以了解下2020-10-10
DBeaver連接本地MySQL并創(chuàng)建數(shù)據(jù)庫(kù)/表的基礎(chǔ)操作教程
DBeaver是一款功能強(qiáng)大的數(shù)據(jù)庫(kù)管理工具,支持創(chuàng)建多種數(shù)據(jù)庫(kù),包括達(dá)夢(mèng)數(shù)據(jù)庫(kù),這篇文章主要給大家介紹了關(guān)于DBeaver連接本地MySQL并創(chuàng)建數(shù)據(jù)庫(kù)/表的基礎(chǔ)操作教程,需要的朋友可以參考下2024-02-02
MySQL中臨時(shí)表的基本創(chuàng)建與使用教程
這篇文章主要介紹了MySQL中臨時(shí)表的基本創(chuàng)建與使用教程,注意臨時(shí)表中數(shù)據(jù)的清空問(wèn)題,需要的朋友可以參考下2015-12-12
mysql中order by與group by的區(qū)別
以下是對(duì)mysql中order by與group by的區(qū)別進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-07-07

