MySQL鎖機(jī)制

一、鎖介紹
鎖是計(jì)算機(jī)協(xié)調(diào)多個(gè)進(jìn)程或線程并發(fā)訪問(wèn)某一資源的機(jī)制。

在數(shù)據(jù)庫(kù)中,除傳統(tǒng)的計(jì)算資源(如CPU、RAM、I/O等)的爭(zhēng)用以外,數(shù)據(jù)也是一種供許多用戶共享的資源。如何保證數(shù)據(jù)并發(fā)訪問(wèn)的一致性、有效性是所有數(shù)據(jù)庫(kù)必須解決的一個(gè)問(wèn)題,鎖沖突也是影響數(shù)據(jù)庫(kù)并發(fā)訪問(wèn)性能的一個(gè)重要因素。從這個(gè)角度來(lái)說(shuō),鎖對(duì)數(shù)據(jù)庫(kù)而言顯得尤其重要,也更加復(fù)雜。

分類
從對(duì)數(shù)據(jù)操作的類型(讀\寫(xiě))分

  • 讀鎖(共享鎖):針對(duì)同一份數(shù)據(jù),多個(gè)讀操作可以同時(shí)進(jìn)行而不會(huì)互相影響。
  • 寫(xiě)鎖(排它鎖):當(dāng)前寫(xiě)操作沒(méi)有完成前,它會(huì)阻斷其他寫(xiě)鎖和讀鎖。

從對(duì)數(shù)據(jù)操作的粒度分

為了盡可能提高數(shù)據(jù)庫(kù)的并發(fā)度,每次鎖定的數(shù)據(jù)范圍越小越好,理論上每次只鎖定當(dāng)前操作的數(shù)據(jù)的方案會(huì)得到最大的并發(fā)度,但是管理鎖是很耗資源的事情(涉及獲取,檢查,釋放鎖等動(dòng)作),因此數(shù)據(jù)庫(kù)系統(tǒng)需要在高并發(fā)響應(yīng)和系統(tǒng)性能兩方面進(jìn)行平衡,這樣就產(chǎn)生了“鎖粒度(Lock granularity)”的概念。

一種提高共享資源并發(fā)發(fā)性的方式是讓鎖定對(duì)象更有選擇性。盡量只鎖定需要修改的部分?jǐn)?shù)據(jù),而不是所有的資源。更理想的方式是,只對(duì)會(huì)修改的數(shù)據(jù)片進(jìn)行精確的鎖定。任何時(shí)候,在給定的資源上,鎖定的數(shù)據(jù)量越少,則系統(tǒng)的并發(fā)程度越高,只要相互之間不發(fā)生沖突即可。

  • 表鎖
  • 行鎖

二、表鎖

2.1 特點(diǎn)

偏向MyISAM存儲(chǔ)引擎,開(kāi)銷小,加鎖快;無(wú)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。

2.2 建表SQL

 
【表級(jí)鎖分析--建表SQL】
 
create table mylock(
 id int not null primary key auto_increment,
 name varchar(20)
)engine myisam;
 
insert into mylock(name) values('a');
insert into mylock(name) values('b');
insert into mylock(name) values('c');
insert into mylock(name) values('d');
insert into mylock(name) values('e');
 
select * from mylock;
 
【手動(dòng)增加表鎖】
 lock table 表名字1 read(write),表名字2 read(write),其它;
【查看表上加過(guò)的鎖】
  show open tables;
 
【釋放表鎖】
unlock tables;

2.2.1 加讀鎖

為mylock表加read鎖(讀阻塞寫(xiě)例子)




2.2.2 加寫(xiě)鎖

mylockwrite(MyISAM)



2.2.3 結(jié)論

MyISAM在執(zhí)行查詢語(yǔ)句(SELECT)前,會(huì)自動(dòng)給涉及的所有表加讀鎖,在執(zhí)行增刪改操作前,會(huì)自動(dòng)給涉及的表加寫(xiě)鎖。
MySQL的表級(jí)鎖有兩種模式:
表共享讀鎖(Table Read Lock)
表獨(dú)占寫(xiě)鎖(Table Write Lock)


結(jié)論:
結(jié)合上表,所以對(duì)MyISAM表進(jìn)行操作,會(huì)有以下情況:
1、對(duì)MyISAM表的讀操作(加讀鎖),不會(huì)阻塞其他進(jìn)程對(duì)同一表的讀請(qǐng)求,但會(huì)阻塞對(duì)同一表的寫(xiě)請(qǐng)求。只有當(dāng)讀鎖釋放后,才會(huì)執(zhí)行其它進(jìn)程的寫(xiě)操作。
2、對(duì)MyISAM表的寫(xiě)操作(加寫(xiě)鎖),會(huì)阻塞其他進(jìn)程對(duì)同一表的讀和寫(xiě)操作,只有當(dāng)寫(xiě)鎖釋放后,才會(huì)執(zhí)行其它進(jìn)程的讀寫(xiě)操作。
簡(jiǎn)而言之,就是讀鎖會(huì)阻塞寫(xiě),但是不會(huì)堵塞讀。而寫(xiě)鎖則會(huì)把讀和寫(xiě)都堵塞

三、行鎖

3.1 特點(diǎn)

  • 偏向InnoDB存儲(chǔ)引擎,開(kāi)銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
  • InnoDB與MyISAM的最大不同有兩點(diǎn):一是支持事務(wù)(TRANSACTION);二是采用了行級(jí)鎖
  • 行鎖支持事務(wù)

3.2 建表SQL

 
create table test_innodb_lock (a int(11),b varchar(16))engine=innodb;
 
insert into test_innodb_lock values(1,'b2');
insert into test_innodb_lock values(3,'3');
insert into test_innodb_lock values(4,'4000');
insert into test_innodb_lock values(5,'5000');
insert into test_innodb_lock values(6,'6000');
insert into test_innodb_lock values(7,'7000');
insert into test_innodb_lock values(8,'8000');
insert into test_innodb_lock values(9,'9000');
insert into test_innodb_lock values(1,'b1');
 
create index test_innodb_a_ind on test_innodb_lock(a);
 
create index test_innodb_lock_b_ind on test_innodb_lock(b);
 
select * from test_innodb_lock;

3.3 示例

3.4 無(wú)索引行鎖會(huì)升級(jí)為表鎖

3.4 Select也可以加鎖

讀鎖

共享鎖(Share Lock)

共享鎖又稱讀鎖,是讀取操作創(chuàng)建的鎖。其他用戶可以并發(fā)讀取數(shù)據(jù),但任何事務(wù)都不能對(duì)數(shù)據(jù)進(jìn)行修改(獲取數(shù)據(jù)上的排他鎖),直到已釋放所有共享鎖。
如果事務(wù)T對(duì)數(shù)據(jù)A加上共享鎖后,則其他事務(wù)只能對(duì)A再加共享鎖,不能加排他鎖。獲準(zhǔn)共享鎖的事務(wù)只能讀數(shù)據(jù),不能修改數(shù)據(jù)。

用法
SELECT ... LOCK IN SHARE MODE;

在查詢語(yǔ)句后面增加 LOCK IN SHARE MODE ,Mysql會(huì)對(duì)查詢結(jié)果中的每行都加共享鎖,當(dāng)沒(méi)有其他線程對(duì)查詢結(jié)果集中的任何一行使用排他鎖時(shí),可以成功申請(qǐng)共享鎖,否則會(huì)被阻塞。其他線程也可以讀取使用了共享鎖的表(行?),而且這些線程讀取的是同一個(gè)版本的數(shù)據(jù)。

寫(xiě)鎖

排他鎖(eXclusive Lock)

共享鎖又稱寫(xiě)鎖,如果事務(wù)T對(duì)數(shù)據(jù)A加上排他鎖后,則其他事務(wù)不能再對(duì)A加任任何類型的封鎖。獲準(zhǔn)排他鎖的事務(wù)既能讀數(shù)據(jù),又能修改數(shù)據(jù)。

用法
SELECT ... FOR UPDATE;

在查詢語(yǔ)句后面增加 FOR UPDATE ,Mysql會(huì)對(duì)查詢結(jié)果中的每行都加排他鎖,當(dāng)沒(méi)有其他線程對(duì)查詢結(jié)果集中的任何一行使用排他鎖時(shí),可以成功申請(qǐng)排他鎖,否則會(huì)被阻塞。

3.5 間隙鎖危害

間隙鎖帶來(lái)的插入問(wèn)題



【什么是間隙鎖】
當(dāng)我們用范圍條件而不是相等條件檢索數(shù)據(jù),并請(qǐng)求共享或排他鎖時(shí),InnoDB會(huì)給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加鎖;對(duì)于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做“間隙(GAP)”,
InnoDB也會(huì)對(duì)這個(gè)“間隙”加鎖,這種鎖機(jī)制就是所謂的間隙鎖(GAP Lock)。

【危害】
因?yàn)镼uery執(zhí)行過(guò)程中通過(guò)過(guò)范圍查找的話,他會(huì)鎖定整個(gè)范圍內(nèi)所有的索引鍵值,即使這個(gè)鍵值并不存在。
間隙鎖有一個(gè)比較致命的弱點(diǎn),就是當(dāng)鎖定一個(gè)范圍鍵值之后,即使某些不存在的鍵值也會(huì)被無(wú)辜的鎖定,而造成在鎖定的時(shí)候無(wú)法插入鎖定鍵值范圍內(nèi)的任何數(shù)據(jù)。在某些場(chǎng)景下這可能會(huì)對(duì)性能造成很大的危害

3.6 結(jié)論

Innodb存儲(chǔ)引擎由于實(shí)現(xiàn)了行級(jí)鎖定,雖然在鎖定機(jī)制的實(shí)現(xiàn)方面所帶來(lái)的性能損耗可能比表級(jí)鎖定會(huì)要更高一些,但是在整體并發(fā)處理能力方面要遠(yuǎn)遠(yuǎn)優(yōu)于MyISAM的表級(jí)鎖定的。當(dāng)系統(tǒng)并發(fā)量較高的時(shí)候,Innodb的整體性能和MyISAM相比就會(huì)有比較明顯的優(yōu)勢(shì)了。

但是,Innodb的行級(jí)鎖定同樣也有其脆弱的一面,當(dāng)我們使用不當(dāng)?shù)臅r(shí)候,可能會(huì)讓Innodb的整體性能表現(xiàn)不僅不能比MyISAM高,甚至可能會(huì)更差。

3.7 如何分析行鎖定

【如何分析行鎖定】
通過(guò)檢查InnoDB_row_lock狀態(tài)變量來(lái)分析系統(tǒng)上的行鎖的爭(zhēng)奪情況
mysql>show status like 'innodb_row_lock%';



對(duì)各個(gè)狀態(tài)量的說(shuō)明如下:

Innodb_row_lock_current_waits:當(dāng)前正在等待鎖定的數(shù)量;
Innodb_row_lock_time:從系統(tǒng)啟動(dòng)到現(xiàn)在鎖定總時(shí)間長(zhǎng)度;
Innodb_row_lock_time_avg:每次等待所花平均時(shí)間;
Innodb_row_lock_time_max:從系統(tǒng)啟動(dòng)到現(xiàn)在等待最常的一次所花的時(shí)間;
Innodb_row_lock_waits:系統(tǒng)啟動(dòng)后到現(xiàn)在總共等待的次數(shù);
對(duì)于這5個(gè)狀態(tài)變量,比較重要的主要是
Innodb_row_lock_time_avg(等待平均時(shí)長(zhǎng)),
Innodb_row_lock_waits(等待總次數(shù))
Innodb_row_lock_time(等待總時(shí)長(zhǎng))這三項(xiàng)。
尤其是當(dāng)?shù)却螖?shù)很高,而且每次等待時(shí)長(zhǎng)也不小的時(shí)候,我們就需要分析系統(tǒng)中為什么會(huì)有如此多的等待,然后根據(jù)分析結(jié)果著手指定優(yōu)化計(jì)劃。

最后可以通過(guò)
SELECT * FROM information_schema.INNODB_TRX\G;
來(lái)查詢正在被鎖阻塞的sql語(yǔ)句。

3.8 優(yōu)化建議

  • 盡可能讓所有數(shù)據(jù)檢索都通過(guò)索引來(lái)完成,避免無(wú)索引行鎖升級(jí)為表鎖。
  • 盡可能較少檢索條件,避免間隙鎖
  • 盡量控制事務(wù)大小,減少鎖定資源量和時(shí)間長(zhǎng)度
  • 鎖住某行后,盡量不要去調(diào)別的行或表,趕緊處理被鎖住的行然后釋放掉鎖。
  • 涉及相同表的事務(wù),對(duì)于調(diào)用表的順序盡量保持一致。
  • 在業(yè)務(wù)環(huán)境允許的情況下,盡可能低級(jí)別事務(wù)隔離

四、頁(yè)鎖
開(kāi)銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容