MYSQL中的鎖:
創(chuàng)新互聯(lián)基于成都重慶香港及美國等地區(qū)分布式IDC機(jī)房數(shù)據(jù)中心構(gòu)建的電信大帶寬,聯(lián)通大帶寬,移動大帶寬,多線BGP大帶寬租用,是為眾多客戶提供專業(yè)服務(wù)器托管報價,主機(jī)托管價格性價比高,為金融證券行業(yè)服務(wù)器托管機(jī)柜,ai人工智能服務(wù)器托管提供bgp線路100M獨(dú)享,G口帶寬及機(jī)柜租用的專業(yè)成都idc公司。
語法 :
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【鎖表】
UNLOCK TABLES 【釋放表】
Read:讀鎖|共享鎖 : 所有的客戶端只能讀這個表不能寫這個表
Write:寫鎖|排它鎖: 所有當(dāng)前鎖定客戶端可以操作這個表,其他客戶端只能阻塞
注意:在鎖表的過程中只能操作被鎖定的表,如果要操作其他表,必須把所有要操作的表都鎖定起來!
PHP中的文件鎖 (鎖的是文件,不是表)
文件鎖的文件與表有什么關(guān)系?:一點(diǎn)關(guān)系也沒有,與令牌相似,誰拿到誰操作。所以表根本沒鎖。
測試時,有個文件就行,叫什么名無所謂
眾所周知,innodb是默認(rèn)行鎖,當(dāng)然也支持表鎖。如下是對于行鎖的算法進(jìn)行的一些實(shí)驗(yàn)。
鎖的算法為:我知道是行鎖,但是是如何鎖的,鎖多少數(shù)據(jù)
假如有個索引是:[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ù)讀隔離級別下,innodb默認(rèn)使用的是next-key lock算法,當(dāng)查詢的索引是主鍵或者唯一索引的情況下,才會退化為record lock,在使用next-key lock算法時,不僅僅會鎖住范圍,還會給范圍最后的一個鍵值加一個gap lock。
其中l(wèi)ockmode中的X鎖為左邊會話中的鎖,因?yàn)樾枰@式的commit之后才會釋放鎖,第二個S鎖,為右邊的共享鎖,因?yàn)橹麈IID為1的已經(jīng)被鎖住了,所以處于鎖等待狀態(tài),鎖的類型為record lock
使用輔助索引a=8進(jìn)行操作,這個時候理論應(yīng)該對主鍵索引加record lock 則 主鍵ID=8的被鎖,然后輔助索引被加next-key lock 則為:
(7,8] 然后對下一個鍵值加gap鎖,則為:(8,11)
所以目前被鎖住的記錄為:
1.主鍵為8的被鎖
2.輔助索引8的被鎖
3.輔助索引8到11之間的被鎖,意味著你這個時候往8到11之間寫數(shù)據(jù)會報錯
當(dāng)使用范圍條件進(jìn)行更新時,此時肯定是需要加X鎖的,我是用的也是主鍵,所以按照理論應(yīng)該是加的record lock ,但是卻加了gap lock,因?yàn)椴迦胫禐?0的阻塞了,查看information 也提示X.GAP
這個有點(diǎn)暈為啥主鍵變成了next-key lock ,不應(yīng)該是record lock么?
update20200515
在知乎看到的一個解釋:
即,在無論使用主鍵索引還是非主鍵索引的時候,請求共享鎖或者排他鎖,innodb會給范圍內(nèi)的記錄加鎖,而范圍內(nèi)的間隙也會被加鎖,
例如一個表t 的 id為1,2,3,7,10
假如執(zhí)行如下:
select * from t where id =3 for update
那么這個時候執(zhí)行
insert into t(id) values(8) 會被阻塞,因?yàn)槭窃谡埱笈潘i時使用了范圍,所以[3,10],甚至10以后的任何數(shù)據(jù)都無法插入。
執(zhí)行
select * from t where id =3 lock in share mode
insert into t(id) values(8) 會被阻塞,因?yàn)槭窃谡埱蠊蚕礞i時使用了范圍,所以[3,10],甚至10以后的任何數(shù)據(jù)都無法插入。
幻讀是同一事務(wù)下,連續(xù)執(zhí)行兩次同樣的sql可能導(dǎo)致不同的結(jié)果,第二次返回的數(shù)據(jù)可能導(dǎo)致以前不存在的行。
同時一般會問它和臟讀的區(qū)別,臟讀為讀取到其他事務(wù)未提交的數(shù)據(jù),但是幻讀是讀取的其他事務(wù)已經(jīng)提交的數(shù)據(jù)。
reference:
SELECT ... LOCK IN SHARE MODE sets a shared mode lock on the rows read
你可以這樣寫SQL
SELECT * FROM table_name LOCK IN SHARE MODE
如果在transaction1(Tr1)進(jìn)行一個
select * from table1 where id 4 lock in share mode.
這里會在table1上加一個next_key lock(間隙鎖),基本原理是什么呢?大致是這樣的,內(nèi)存中有一個lock hash。是一個key(類似于tableid+pageid+offset)到value(所加的鎖)--- 這就是行鎖的原理。所以 id4的話,會給0 1 2 4(假設(shè)當(dāng)前數(shù)據(jù)庫沒有3)加上行鎖,這樣就保證了不會出現(xiàn)插入id=3.5這種事情的發(fā)生。
MySQL 5.1支持對MyISAM和MEMORY表進(jìn)行表級鎖定,對BDB表進(jìn)行頁級鎖定,對InnoDB表進(jìn)行行級鎖定。
如果不能同時插入,為了在一個表中進(jìn)行多次INSERT和SELECT操作,可以在臨時表中插入行并且立即用臨時表中的記錄更新真正的表。
這可用下列代碼做到:
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;
用以下sql語句就可以實(shí)現(xiàn)行鎖定,前提是innodb模式:
SELECT ... FOR UPDATE
或者
SELECT ... LOCK IN SHARE MODE