mysql 為并發(fā)事務(wù)同時(shí)對(duì)一條記錄進(jìn)行讀寫時(shí),提出了兩種解決方案:
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對(duì)這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡(jiǎn)單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:申請(qǐng)域名、虛擬空間、營(yíng)銷軟件、網(wǎng)站建設(shè)、代縣網(wǎng)站維護(hù)、網(wǎng)站推廣。
1)使用 mvcc 的方法,實(shí)現(xiàn)多事務(wù)的并發(fā)讀寫,但是這種讀只是“快照讀”,一般讀的是歷史版本數(shù)據(jù),還有一種是“當(dāng)前讀”,一般加鎖實(shí)現(xiàn)“當(dāng)前讀”,或者 insert、update、delete 也是當(dāng)前讀。
2)使用加鎖的方法,鎖分為共享鎖(讀鎖),排他鎖(寫鎖)
快照讀:就是select
當(dāng)前讀:特殊的讀操作,插入/更新/刪除操作,屬于當(dāng)前讀,處理的都是當(dāng)前的數(shù)據(jù),需要加鎖。
mysql 在 RR 級(jí)別怎么處理幻讀的呢?一般來說,RR 級(jí)別通過 mvcc 機(jī)制,保證讀到低于后面事務(wù)的數(shù)據(jù)。但是 select for update 不會(huì)觸發(fā) mvcc,它是當(dāng)前讀。如果后面事務(wù)插入數(shù)據(jù)并提交,那么在 RR 級(jí)別就會(huì)讀到插入的數(shù)據(jù)。所以,mysql 使用 行鎖 + gap 鎖(簡(jiǎn)稱 next-key 鎖)來防止當(dāng)前讀的時(shí)候插入。
Gap Lock在InnoDB的唯一作用就是防止其他事務(wù)的插入操作,以此防止幻讀的發(fā)生。
Innodb自動(dòng)使用間隙鎖的條件:
眾所周知,innodb是默認(rèn)行鎖,當(dāng)然也支持表鎖。如下是對(duì)于行鎖的算法進(jìn)行的一些實(shí)驗(yàn)。
鎖的算法為:我知道是行鎖,但是是如何鎖的,鎖多少數(shù)據(jù)
假如有個(gè)索引是:[1,2,3,7]
record lock 鎖的是 1,2,3,7
gap lock 鎖的是 (- ,1),(2,3),(3,7),(7,+ )反正鎖的就是區(qū)間,不是行
next-key lock鎖的是 (- ,1],[2,3),[3,7),[ 7,+ )既鎖范圍也鎖行
Innodb鎖算法規(guī)則如下:
在可重復(fù)讀隔離級(jí)別下,innodb默認(rèn)使用的是next-key lock算法,當(dāng)查詢的索引是主鍵或者唯一索引的情況下,才會(huì)退化為record lock,在使用next-key lock算法時(shí),不僅僅會(huì)鎖住范圍,還會(huì)給范圍最后的一個(gè)鍵值加一個(gè)gap lock。
其中l(wèi)ockmode中的X鎖為左邊會(huì)話中的鎖,因?yàn)樾枰@式的commit之后才會(huì)釋放鎖,第二個(gè)S鎖,為右邊的共享鎖,因?yàn)橹麈IID為1的已經(jīng)被鎖住了,所以處于鎖等待狀態(tài),鎖的類型為record lock
使用輔助索引a=8進(jìn)行操作,這個(gè)時(shí)候理論應(yīng)該對(duì)主鍵索引加record lock 則 主鍵ID=8的被鎖,然后輔助索引被加next-key lock 則為:
(7,8] 然后對(duì)下一個(gè)鍵值加gap鎖,則為:(8,11)
所以目前被鎖住的記錄為:
1.主鍵為8的被鎖
2.輔助索引8的被鎖
3.輔助索引8到11之間的被鎖,意味著你這個(gè)時(shí)候往8到11之間寫數(shù)據(jù)會(huì)報(bào)錯(cuò)
當(dāng)使用范圍條件進(jìn)行更新時(shí),此時(shí)肯定是需要加X鎖的,我是用的也是主鍵,所以按照理論應(yīng)該是加的record lock ,但是卻加了gap lock,因?yàn)椴迦胫禐?0的阻塞了,查看information 也提示X.GAP
這個(gè)有點(diǎn)暈為啥主鍵變成了next-key lock ,不應(yīng)該是record lock么?
update20200515
在知乎看到的一個(gè)解釋:
即,在無論使用主鍵索引還是非主鍵索引的時(shí)候,請(qǐng)求共享鎖或者排他鎖,innodb會(huì)給范圍內(nèi)的記錄加鎖,而范圍內(nèi)的間隙也會(huì)被加鎖,
例如一個(gè)表t 的 id為1,2,3,7,10
假如執(zhí)行如下:
select * from t where id =3 for update
那么這個(gè)時(shí)候執(zhí)行
insert into t(id) values(8) 會(huì)被阻塞,因?yàn)槭窃谡?qǐng)求排他鎖時(shí)使用了范圍,所以[3,10],甚至10以后的任何數(shù)據(jù)都無法插入。
執(zhí)行
select * from t where id =3 lock in share mode
insert into t(id) values(8) 會(huì)被阻塞,因?yàn)槭窃谡?qǐng)求共享鎖時(shí)使用了范圍,所以[3,10],甚至10以后的任何數(shù)據(jù)都無法插入。
幻讀是同一事務(wù)下,連續(xù)執(zhí)行兩次同樣的sql可能導(dǎo)致不同的結(jié)果,第二次返回的數(shù)據(jù)可能導(dǎo)致以前不存在的行。
同時(shí)一般會(huì)問它和臟讀的區(qū)別,臟讀為讀取到其他事務(wù)未提交的數(shù)據(jù),但是幻讀是讀取的其他事務(wù)已經(jīng)提交的數(shù)據(jù)。
reference:
for update 的作用是在查詢的時(shí)候?yàn)樾屑由吓潘i,當(dāng)一個(gè)事務(wù)的操作未完成時(shí)候,其他事務(wù)可以讀取但是不能寫入或更新。
它的典型使用場(chǎng)景是 高并發(fā)并且對(duì)于數(shù)據(jù)的準(zhǔn)確性有很高要求 ,比如金錢、庫存等,一般這種操作都是很長(zhǎng)一串并且開啟事務(wù)的,假如現(xiàn)在要對(duì)庫存進(jìn)行操作,在剛開始讀的時(shí)候是1,然后馬上另外一個(gè)進(jìn)程將庫存更新為0了,但事務(wù)還沒結(jié)束,會(huì)一直用1進(jìn)行后續(xù)的邏輯,就會(huì)有問題,所以需要用for upate 加鎖防止出錯(cuò)。
行鎖的具體實(shí)現(xiàn)算法有三種:record lock、gap lock以及next-key lock。
只在可重復(fù)讀或以上隔離級(jí)別下的特定操作才會(huì)取得 gap lock 或 next-key lock,在 Select、Update 和 Delete 時(shí),除了基于唯一索引的查詢之外,其它索引查詢時(shí)都會(huì)獲取 gap lock 或 next-key lock,即鎖住其掃描的范圍。主鍵索引也屬于唯一索引,所以主鍵索引是不會(huì)使用 gap lock 或 next-key lock
for update 僅適用于InnoDB,并且必須開啟事務(wù),在begin與commit之間才生效。
select 語句默認(rèn)不獲取任何鎖,所以是可以讀被其它事務(wù)持有排它鎖的數(shù)據(jù)的!
InnoDB 既實(shí)現(xiàn)了行鎖,也實(shí)現(xiàn)了表鎖。
當(dāng)有明確指定的主鍵/索引時(shí)候,是行級(jí)鎖,否則是表級(jí)鎖
假設(shè)表 user,存在有id跟name字段,id是主鍵,有5條數(shù)據(jù)。
明確指定主鍵,并且有此記錄,行級(jí)鎖
無主鍵/索引,表級(jí)鎖
主鍵/索引不明確,表級(jí)鎖
明確指定主鍵/索引,若查無此記錄,無鎖
參考博文:
注意事項(xiàng):session1中沒有commit之前,該數(shù)據(jù)行是鎖定的,其他的session修改該行數(shù)據(jù)時(shí)會(huì)進(jìn)入堵塞狀態(tài)。
MySQL 5.1支持對(duì)MyISAM和MEMORY表進(jìn)行表級(jí)鎖定,對(duì)BDB表進(jìn)行頁級(jí)鎖定,對(duì)InnoDB表進(jìn)行行級(jí)鎖定。
如果不能同時(shí)插入,為了在一個(gè)表中進(jìn)行多次INSERT和SELECT操作,可以在臨時(shí)表中插入行并且立即用臨時(shí)表中的記錄更新真正的表。
這可用下列代碼做到:
mysql LOCK TABLES real_table WRITE, insert_table WRITE;
mysql INSERT INTO real_table SELECT * FROM insert_table;
mysql TRUNCATE TABLE insert_table;
mysql UNLOCK TABLES;
1、在mysql數(shù)據(jù)庫中如何鎖定一行數(shù)據(jù),保證不被其他的操作影響。
2、從對(duì)數(shù)據(jù)的操作類型分為讀鎖和寫鎖。從對(duì)數(shù)據(jù)操作的粒度來分:表鎖和行鎖。
3、現(xiàn)在我們建立一個(gè)表來演示數(shù)據(jù)庫的行鎖講解。
4、行鎖基本演示如下圖所示。
5、如果兩個(gè)會(huì)話操作的是不同的行,就不會(huì)互相阻塞了。