目的
解決因資源共享而造成的并發(fā)問題痛侍。
示例:買最后一件衣服X
A:X買:X加鎖->試衣服...下單..付款..打包->X解鎖
B:X買:發(fā)現X已被加鎖,等待X解鎖磷杏,X已售空
分類:
操作類型:
a.讀鎖(共享鎖):對同一個數據(衣服)吏饿,多個讀操作可以同時進行,互不干擾憋活。
b.寫鎖(互斥鎖):如果當前寫操作沒有完畢(買衣服的一系列操作),則無法進行其他的讀操作虱黄、寫操作
操作范圍:
a.表鎖:一次性對一張表整體加鎖悦即。如MyISAM存儲引擎使用表鎖,開銷小、加鎖快盐欺;無死鎖;但鎖的范圍大仅醇,容易發(fā)生鎖沖突、并發(fā)度低。
b.行鎖:一次性對一條數據加鎖擎勘。如InnoDB存儲引擎使用行鎖然评,開銷大,加鎖慢叶摄;容易出現死鎖属韧;鎖的范圍較小,不易發(fā)生鎖沖突蛤吓,并發(fā)度高(很小概率發(fā)生高并發(fā)問題:臟讀宵喂、幻讀、不可重復度会傲、丟失更新等問題)锅棕。
c.頁鎖
示例:
(1)表鎖:--自增操作MYSQL/SQLSERVER支持;oracle需要借助于序列來實現自增
createtabletablelock
(
idintprimarykeyauto_increment,
namevarchar(20)
)enginemyisam;
insertintotablelock(name)values('a1');
insertintotablelock(name)values('a2');
insertintotablelock(name)values('a3');
insertintotablelock(name)values('a4');
insertintotablelock(name)values('a5');
commit;
增加鎖:
locaktable表1read/write,表2read/write,...
查看加鎖的表:
showopentables;
會話:session:每一個訪問數據的dos命令行淌山、數據庫客戶端工具都是一個會話
===加讀鎖:
會話0:
locktabletablelockread;
select*fromtablelock;--讀(查)裸燎,可以
deletefromtablelockwhereid=1;--寫(增刪改),不可以
select*fromemp;--讀泼疑,不可以
deletefromempwhereeid=1;--寫德绿,不可以
結論1:
--如果某一個會話對A表加了read鎖,則該會話可以對A表進行讀操作退渗、不能進行寫操作移稳;且該會話不能對其他表進行讀、寫操作氓辣。
--即如果給A表加了讀鎖秒裕,則當前會話只能對A表進行讀操作。
會話1(其他會話):
select*fromtablelock;--讀(查)钞啸,可以
deletefromtablelockwhereid=1;--寫几蜻,會“等待”會話0將鎖釋放
會話1(其他會話):
select*fromemp;--讀(查),可以
deletefromempwhereeno=1;--寫体斩,可以
結論2:
--總結:
會話0給A表加了鎖梭稚;其他會話的操作:a.可以對其他表(A表以外的表)進行讀、寫操作
b.對A表:讀-可以絮吵;寫-需要等待釋放鎖弧烤。
釋放鎖:unlocktables;
===加寫鎖:
會話0:
locktabletablelockwrite;
當前會話(會話0)可以對加了寫鎖的表進行任何操作(增刪改查);但是不能操作(增刪改查)其他表
其他會話:
對會話0中加寫鎖的表可以進行增刪改查的前提是:等待會話0釋放寫鎖
MySQL表級鎖的鎖模式
MyISAM在執(zhí)行查詢語句(SELECT)前蹬敲,會自動給涉及的所有表加讀鎖暇昂,
在執(zhí)行更新操作(DML)前莺戒,會自動給涉及的表加寫鎖。
所以對MyISAM表進行操作急波,會有以下情況:
a从铲、對MyISAM表的讀操作(加讀鎖),不會阻塞其他進程(會話)對同一表的讀請求澄暮,
但會阻塞對同一表的寫請求名段。只有當讀鎖釋放后,才會執(zhí)行其它進程的寫操作泣懊。
b伸辟、對MyISAM表的寫操作(加寫鎖),會阻塞其他進程(會話)對同一表的讀和寫操作馍刮,
只有當寫鎖釋放后信夫,才會執(zhí)行其它進程的讀寫操作。
分析表鎖定:
查看哪些表加了鎖:showopentables;1代表被加了鎖
分析表鎖定的嚴重程度:showstatuslike'table%';
Table_locks_immediate:即可能獲取到的鎖數
Table_locks_waited:需要等待的表鎖數(如果該值越大卡啰,說明存在越大的鎖競爭)
一般建議:
Table_locks_immediate/Table_locks_waited>5000忙迁,建議采用InnoDB引擎,否則MyISAM引擎
(2)行表(InnoDB)
createtablelinelock(
idint(5)primarykeyauto_increment,
namevarchar(20)
)engine=innodb;
insertintolinelock(name)values('1');
insertintolinelock(name)values('2');
insertintolinelock(name)values('3');
insertintolinelock(name)values('4');
insertintolinelock(name)values('5');
--mysql默認自動commit;oracle默認不會自動commit;
為了研究行鎖碎乃,暫時將自動commit關閉;setautocommit=0;以后需要通過commit
會話0:寫操作
insertintolinelockvalues('a6');
會話1:寫操作同樣的數據
updatelinelocksetname='ax'whereid=6;
對行鎖情況:
1.如果會話x對某條數據a進行DML操作(研究時:關閉了自動commit的情況下)姊扔,則其他會話必須等待會話x結束事務(commit/rollback)后才能對數據a進行操作。
2.表鎖是通過unlocktables梅誓,也可以通過事務解鎖;行鎖是通過事務解鎖恰梢。
行鎖,操作不同數據:
會話0:寫操作
insertintolinelockvalues(8,'a8');
會話1:寫操作梗掰,不同的數據
updatelinelocksetname='ax'whereid=5;
行鎖嵌言,一次鎖一行數據;因此如果操作的是不同數據及穗,則不干擾摧茴。
行鎖的注意事項:
a.如果沒有索引,則行鎖會轉為表鎖
showindexfromlinelock;
altertablelinelockaddindexidx_linelock_name(name);
會話0:寫操作
updatelinelocksetname='ai'wherename='3';
會話1:寫操作埂陆,不同的數據
updatelinelocksetname='aiX'wherename='4';
會話0:寫操作
updatelinelocksetname='ai'wherename=3;
會話1:寫操作苛白,不同的數據
updatelinelocksetname='aiX'wherename=4;
--可以發(fā)現,數據被阻塞了(加鎖)
--原因:如果索引類發(fā)生了類型轉換焚虱,則索引失效购裙。因此此次操作,會從行鎖轉為表鎖鹃栽。
b.行鎖的一種特殊情況:間隙鎖:值在范圍內躏率,但卻不存在
--此時linelock表中沒有id=7的數據
updatelinelocksetname='x'whereid>1andid<9;--即在此where范圍中,沒有id=7的數據,則id=7的數據成為間隙薇芝。
間隙:Mysql會自動給間隙加索->間隙鎖蓬抄。即本題會自動給id=7的數據加間隙鎖(行鎖)。
行鎖:如果有where夯到,則實際加索的范圍就是where后面的范圍(不是實際的值)
如何僅僅是查詢數據倡鲸,能否加鎖?可以forupdate
研究學習時黄娘,將自動提交關閉:
setautocommit=0;
starttransaction;
begin;
select*fromlinelockwhereid=2forupdate;
通過forupdate對query語句進行加鎖。
行鎖:
InnoDB默認采用行鎖克滴;
缺點:比表鎖性能損耗大逼争。
優(yōu)點:并發(fā)能力強,效率高劝赔。
因此建議誓焦,高并發(fā)用InnoDB,否則用MyISAM着帽。
行鎖分析:
showstatuslike'%innodb_row_lock%';
Innodb_row_lock_current_waits:當前正在等待鎖的數量
Innodb_row_lock_time:等待總時長杂伟。從系統(tǒng)啟到現在一共等待的時間
Innodb_row_lock_time_avg:平均等待時長。從系統(tǒng)啟到現在平均等待的時間
Innodb_row_lock_time_max:最大等待時長仍翰。從系統(tǒng)啟到現在最大一次等待的時間
Innodb_row_lock_waits:等待次數赫粥。從系統(tǒng)啟到現在一共等待的次數