鎖分類(lèi)
????根據(jù)鎖粒度和兼容性劃分
????????????????|----表鎖(MyISAM,InnoDB? 開(kāi)銷(xiāo)小脚粟,加鎖快胆剧,不死鎖,并發(fā)差)? ??
? ??????????????????????|----共享鎖(S鎖):加鎖后其他用戶可讀不可寫(xiě)
? ??????????????????????|----排他鎖(X鎖):加鎖后其他用戶不可讀寫(xiě)
? ??????????????????? ? |----意向共享鎖(IS鎖):innoDB中為了兼容行鎖和表鎖羊壹,并存多個(gè)(表級(jí)別鎖)
????????????????????????|----意向排他鎖(IX鎖):innoDB中為了兼容行鎖和表鎖,只有一個(gè)(表級(jí)別鎖)
? ? ? ? ? ? ? ? |----行鎖(InnoDB ?開(kāi)銷(xiāo)小齐婴,加鎖快油猫,不死鎖,并發(fā)差)? ??
? ??????????????????????|----共享鎖(S鎖):加鎖后其他用戶可讀不可寫(xiě)
? ??????????????????????|----排他鎖(X鎖):加鎖后其他用戶不可寫(xiě)但是可讀(這里是快照讀)D肌G檠!
????????????????|----頁(yè)面鎖(BDB诱担,各項(xiàng)性能居中毡证,會(huì)出現(xiàn)死鎖)
????根據(jù)加鎖機(jī)制劃分
????????????????|----樂(lè)觀鎖:樂(lè)觀的認(rèn)為不會(huì)出現(xiàn)并發(fā),手動(dòng)加一個(gè)版本號(hào)用于判斷(不是mvcc的那個(gè)版本號(hào))
????????????????|----悲觀鎖:行鎖蔫仙,表鎖這些都是悲觀的情竹。
? ? 行鎖的三種算法
????????????????|----記錄鎖:?jiǎn)蝹€(gè)行記錄上的鎖
????????????????|----間隙鎖:鎖定一個(gè)范圍,但不包括記錄本身匀哄。
????????????????|----nextKey鎖:記錄鎖+間隙鎖秦效,鎖定一個(gè)范圍,并且鎖定記錄本身
1.表鎖:
????1.1共享讀鎖(S鎖/共享鎖)
? ? ? ? 顯式加鎖:lock? table? 表名? read? (local)? ??
? ? ? ? 隱式加鎖:select自動(dòng)給涉及到所有表加讀鎖
? ??????解鎖:unlock?tables
? ? ? ? 加鎖之后涎嚼,其他用戶對(duì)同一表可讀不可寫(xiě)阱州。
? ??????LOCAL修飾符表示允許在其他會(huì)話中對(duì)在當(dāng)前會(huì)話中獲取了READ鎖的的表執(zhí)行插入
????1.2獨(dú)占寫(xiě)鎖(X鎖/排他鎖)
????????顯式加鎖:lock? table? 表名? write?
? ??????隱式加鎖:update,delete法梯,insert自動(dòng)給所涉及到的表加寫(xiě)鎖
? ??????解鎖:unlock?tables
? ? ? ? 加鎖之后苔货,其他用戶對(duì)同一表不可讀寫(xiě)
????1.3MyISAM為什么不會(huì)出現(xiàn)死鎖?
? ? ? ? MyISAM在select之前立哑,會(huì)自動(dòng)給涉及到所有表加讀鎖夜惭;在update,delete铛绰,insert之前诈茧,會(huì)自動(dòng)給所涉及到的表加寫(xiě)鎖。這個(gè)過(guò)程都是自動(dòng)的捂掰,不需要用戶使用lock table顯式加鎖敢会。MyISAM總是一次獲得SQL語(yǔ)句所需要的全部鎖曾沈。這也正是MyISAM表不會(huì)出現(xiàn)死鎖的原因。
????1.4MyISAM的并發(fā)插入
????????MyISAM中的系統(tǒng)變量concurrent_insert鸥昏,專(zhuān)門(mén)處理其并發(fā)插入的行為塞俱,其值可為0,1(默認(rèn)值)吏垮,2
????????concurrent_insert = 0障涯,不允許并發(fā)插入
? ? ? ? concurrent_insert = 1,如果MyISAM表中沒(méi)有空洞膳汪,myisam允許在一個(gè)進(jìn)程讀表的同時(shí)像樊,另一個(gè)進(jìn)程從表尾插入記錄
????????concurrent_insert = 2,無(wú)論myisam表中有沒(méi)有空洞旅敷,都允許在表尾并發(fā)插入記錄
? ? 1.5如果兩個(gè)進(jìn)程分別請(qǐng)求讀鎖和寫(xiě)鎖,mysql將如何處理颤霎?
????????寫(xiě)進(jìn)程先獲得鎖媳谁,即使讀請(qǐng)求先到鎖等待隊(duì)列,寫(xiě)請(qǐng)求后到友酱,寫(xiě)鎖也會(huì)插入到讀鎖隊(duì)列晴音。mysql認(rèn)為寫(xiě)請(qǐng)求比讀請(qǐng)求更重要。大量的更新操作會(huì)造成查詢操作很難獲得讀鎖缔杉,從而可能永遠(yuǎn)堵塞锤躁。這就是myisam不太適合于有大量更新操作和查詢操作的原因
? ? ? ? 解決方法:?set? low_priority_updates? = 1? ? 將讀的優(yōu)先級(jí)提高
????1.6意向共享鎖(IS鎖)意向排他鎖(IX鎖)
? ? ? ? 仔細(xì)想想還是把意向鎖放在表鎖下面,原因有二:第一 意向鎖是表級(jí)別的鎖或详,第二 意向鎖的作用是為了兼容表鎖和行鎖系羞,剛好引出下面的行鎖來(lái)。
? ? ? ? 作用:InnoDB為了實(shí)現(xiàn)多粒度鎖機(jī)制霸琴。兼容表鎖和行鎖
? ? ? ? 舉例:假如沒(méi)有意向鎖且行鎖和表鎖兼容椒振,事務(wù)A鎖住表中的一行(寫(xiě)鎖,其他事務(wù)就不可能修改這一行)梧乘,事務(wù)B鎖住整個(gè)表(寫(xiě)鎖澎迎,B可就以隨便修改表內(nèi)數(shù)據(jù)),這樣事務(wù)A选调,事務(wù)B是相悖的
? ? ? ? 意向鎖如何實(shí)現(xiàn)行鎖和表鎖兼容夹供?:還是上面的例子,事務(wù)A申請(qǐng)行鎖(寫(xiě)鎖)仁堪,數(shù)據(jù)庫(kù)會(huì)自動(dòng)先給事務(wù)A申請(qǐng)表的意向排他鎖哮洽。當(dāng)事務(wù)B去申請(qǐng)表的寫(xiě)鎖時(shí)就會(huì)失敗,因?yàn)楸砩嫌幸庀蚺潘i之后事務(wù)B申請(qǐng)表的寫(xiě)鎖時(shí)會(huì)被阻塞
? ? ????如果一個(gè)事務(wù)請(qǐng)求的鎖模式與當(dāng)前的鎖兼容弦聂,InnoDB就請(qǐng)求的鎖授予該事務(wù)袁铐;反之揭蜒,如果兩者兩者不兼容,該事務(wù)就要等待鎖釋放剔桨。 意向鎖是InnoDB自動(dòng)加的屉更,不需用戶干預(yù)。對(duì)于update洒缀、delete和insert語(yǔ)句瑰谜,InnoDB會(huì)自動(dòng)給涉及數(shù)據(jù)集加排他鎖(X);對(duì)于普通select語(yǔ)句树绩,InnoDB不會(huì)加任何鎖萨脑。
? ? ? ? 意向鎖是表級(jí)別鎖。假如此時(shí)你要加一個(gè)表鎖饺饭,意向鎖如果是行級(jí)別鎖則需要遍歷全表
2.行鎖:
? ??????InnoDB行鎖是給索引上的索引項(xiàng)加鎖來(lái)實(shí)現(xiàn)的渤早。只有通過(guò)索引條件檢索數(shù)據(jù),InnoDB才使用行級(jí)鎖瘫俊,否則鹊杖,InnoDB將使用表鎖
? ??2.1共享鎖(S鎖)
????????顯式加鎖:select ...?LOCK IN SHARE MODE
? ? ????隱式加鎖:innoDB的select不會(huì)加任何鎖(這是快照讀,詳情參考mvcc)
????????加鎖之后扛芽,其他用戶對(duì)同一行可讀不可寫(xiě)
????2.2排他鎖(X鎖)? ??
? ? ? ? 顯式加鎖:select ...?FOR UPDATE
? ? ? ? 隱式加鎖:innoDB的update骂蓖,delete,insert操作自動(dòng)給所涉及到的表加排他鎖
? ??????加鎖之后川尖,其他用戶對(duì)同一行不可寫(xiě)但是可讀(因?yàn)閕nnoDB的select默認(rèn)是快照讀登下,不上鎖)
? ? 2.3記錄鎖(Record Locks)
????????記錄鎖就是為某行記錄加鎖,它封鎖該行的索引記錄
????SELECT * FROM table WHERE id = 1 FOR UPDATE;
????????id?列必須為唯一索引列或主鍵列叮喳,查詢語(yǔ)句必須為精準(zhǔn)匹配(=)被芳,不能為?>、<馍悟、like等筐钟。否則上述語(yǔ)句加的鎖就會(huì)變成臨鍵鎖。
????2.4間隙鎖(GAP鎖)
????????當(dāng)我們用范圍條件檢索數(shù)據(jù)并請(qǐng)求共享或排他鎖時(shí)赋朦,InnoDB會(huì)給符合條件的已有數(shù)據(jù)記錄的索引項(xiàng)加記錄鎖篓冲;對(duì)于鍵值在條件范圍內(nèi)但并不存在的記錄,InnoDB也會(huì)對(duì)其加鎖宠哄,這就是間隙鎖?
? ? ? ? 舉例:下圖為表數(shù)據(jù)和索引B的數(shù)據(jù)結(jié)構(gòu)壹将,事務(wù)A拿到了X鎖。事務(wù)B要修改數(shù)據(jù)毛嫉。
? ? ? ? 事務(wù)A:select * from z where b=6 for update?
? ? ? ? 事務(wù)B:update z set b=7 where id=7 (阻塞)
? ? ? ? ? ? ? ? ? ? ?update z set id=6 where id=8?(阻塞)
? ? ? ? 我們可以看到诽俯,不管是將b修改為7還是將id修改為8,都在鎖住的范圍內(nèi)
????2.5臨鍵鎖(next-key鎖)
? ? ? ? 我們可以將next-key理解為一種特殊的算法承粤。
? ??????Next-Key = 記錄鎖 + 間隙鎖? ? ?
????????作用:1.和mvcc一起解決幻讀的問(wèn)題? ? 2.滿足復(fù)制暴区,備份需要
? ? ? ? 假如不使用間隙鎖闯团,其它事務(wù)插入了empid大于100的記錄,那么本事務(wù)再次執(zhí)行上述語(yǔ)句仙粱,前后兩次結(jié)果不一致就會(huì)發(fā)生幻讀房交。
? ? ? ? mysql的恢復(fù)機(jī)制是按照事務(wù)提交的順序記錄sql語(yǔ)句(執(zhí)行binlog中的sql語(yǔ)句),說(shuō)白了,還是不允許出現(xiàn)幻讀的情況
? ? 2.6行鎖爭(zhēng)用情況
????????可以通過(guò)檢查 InnoDB_row_lock 狀態(tài)變量來(lái)分析系統(tǒng)上的行鎖的爭(zhēng)奪情況:
3.死鎖:
3.1什么是死鎖伐割?
????????多個(gè)事務(wù)在同一資源上互相占用形成回路候味。這就是死鎖
3.2死鎖的例子
? ? ? ? 下面是一個(gè)死鎖的例子,事務(wù)A想修改id=2的數(shù)據(jù)隔心,但是必須要事務(wù)B釋放白群。事務(wù)B想要修改id=1的數(shù)據(jù),同樣也在等待事務(wù)A的結(jié)束硬霍。
? ? ? ? t1時(shí)刻 A事務(wù)執(zhí)行:select * from test where id=1 for update;
? ? ? ? t2時(shí)刻 B事務(wù)執(zhí)行:? select * from test where id=2 for update;
? ??????t3時(shí)刻 A事務(wù)執(zhí)行:update test set id=id where id=2;
? ? ????t4時(shí)刻 B事務(wù)執(zhí)行:update test set id=id where id=1;
3.3解決方法:
? ? ? ? 部分或完全回滾其中一個(gè)事務(wù)(?InnoDB默認(rèn)回滾最少行級(jí)排他鎖的事務(wù))
3.4預(yù)防手段:
? ? ? ? 1.innodb_lock_wait_timeout? InnoDB的鎖超時(shí)等待參數(shù)
? ? ? ? 2.合理設(shè)計(jì)索引
? ? ? ? 3.降低隔離級(jí)別(看業(yè)務(wù)是否允許)
? ? ? ? 4.大事務(wù)拆小帜慢,盡量一次性把鎖拿全?
3.5定位死鎖:
????????1.查看隔離級(jí)別????select @@tx_isolation;? ? ? ??
????????2.查看當(dāng)前線程? ? show processlist;
????????3.show innodb status:? 返回結(jié)果中包括死鎖相關(guān)事務(wù)的詳細(xì)信息,如引發(fā)死鎖的 SQL 語(yǔ)句唯卖,事務(wù)已經(jīng)獲得的鎖粱玲,正在等待什么鎖,以及被回滾的事務(wù)等耐床。據(jù)此可以分析死鎖產(chǎn)生的原因和改進(jìn)措施。
? ? ? ? 4.重要的三張鎖的監(jiān)控表innodb_trx楔脯,innodb_locks撩轰,innodb_lock_waits