Mysql體系——鎖

內(nèi)容

  • 鎖種類(lèi)
  • 鎖類(lèi)型
  • 一致性非鎖定讀
  • 一致性鎖定讀
  • 鎖算法

一 鎖種類(lèi)

根據(jù)加鎖的范圍來(lái)說(shuō)竹椒,鎖可以分為:全局鎖滑废、表級(jí)鎖贞滨、行級(jí)鎖

1 全局鎖(FTWRL)

  • 加鎖方式:flush tables with read lock
  • 用途:全局主要用來(lái)全庫(kù)邏輯備份竟痰,加了全局鎖之后盘榨,會(huì)阻塞整庫(kù)其他線程的更新操作郊愧,這個(gè)時(shí)候可以通過(guò)select把整庫(kù)導(dǎo)出到文本做備份朴译;
  • 缺點(diǎn):如果在主庫(kù)執(zhí)行全局鎖,主庫(kù)就停寫(xiě)属铁,如果在備庫(kù)眠寿,那么會(huì)導(dǎo)致主庫(kù)延遲;
  • 還可以用其他方式代替全局鎖嗎焦蘑?
    1. 如果所有表都是innodb表盯拱,并且隔離級(jí)別是可重復(fù)讀的話,可以通過(guò)事務(wù)來(lái)實(shí)現(xiàn),在一個(gè)事務(wù)內(nèi)進(jìn)行讀取數(shù)據(jù)狡逢,事務(wù)開(kāi)啟時(shí)會(huì)生成一個(gè)一致性視圖宁舰,之后在當(dāng)前事務(wù)讀取的數(shù)據(jù)都不會(huì)受其他線程更新影響

2 表級(jí)鎖

  • 種類(lèi):表級(jí)鎖有兩種:表鎖和MDL(metadata lock)
  • 表鎖加鎖:lock tables … read/write
  • MDL:mdl鎖是隱示的加鎖,當(dāng)訪問(wèn)一個(gè)表時(shí)會(huì)被主動(dòng)加上
    1.當(dāng)對(duì)表進(jìn)行增刪改查時(shí)奢浑,會(huì)申請(qǐng)獲取mdl讀鎖蛮艰;當(dāng)進(jìn)行表結(jié)構(gòu)變更時(shí),會(huì)申請(qǐng)mdl寫(xiě)鎖雀彼;
    2.mdl讀鎖之間不阻塞壤蚜,可以用多個(gè)線程同時(shí)獲取同一個(gè)表的mdl讀鎖;mdl讀鎖會(huì)堵塞mdl寫(xiě)鎖徊哑,mdl寫(xiě)鎖會(huì)堵塞mdl 讀寫(xiě)鎖袜刷,當(dāng)一個(gè)表的mdl讀鎖被占用了后,不能再對(duì)該表進(jìn)行表結(jié)構(gòu)變更实柠,ddl會(huì)被堵塞水泉,假設(shè)此時(shí)又有其他的線程來(lái)申請(qǐng)mdl讀鎖,那么這些讀請(qǐng)求都會(huì)被堵塞窒盐,所以如果對(duì)熱點(diǎn)表進(jìn)行ddl操作草则,有可能就會(huì)堵塞大量請(qǐng)求,然后又會(huì)不停重試蟹漓,導(dǎo)致打爆整個(gè)庫(kù)

3 行級(jí)別

  • 兩階段鎖協(xié)議:在innodb事務(wù)中炕横,行鎖是需要的時(shí)候才加上的,但是要等到事務(wù)結(jié)束了才會(huì)釋放鎖葡粒;這個(gè)機(jī)制給我們啟示是:如果你的事務(wù)中需要鎖多個(gè)行份殿,要把最可能造成鎖沖突、最可能影響并發(fā)度的鎖盡量放在事務(wù)的后面去執(zhí)行嗽交;
  • 死鎖和死鎖檢測(cè)
    1.當(dāng)并發(fā)系統(tǒng)中不同線程出現(xiàn)循環(huán)資源依賴(lài)卿嘲,涉及的線程都在等待別的線程釋放資源時(shí),就會(huì)導(dǎo)致這幾個(gè)線程都進(jìn)入無(wú)限等待的狀態(tài)夫壁,稱(chēng)為死鎖
  • 當(dāng)發(fā)生死鎖是有何種策略解決拾枣?
    1. 直接等待,超時(shí)釋放盒让,超時(shí)時(shí)間是有參數(shù):innodb_lock_wait_timeout設(shè)定的梅肤;
      2.發(fā)起死鎖檢測(cè),主動(dòng)回滾死鎖中一個(gè)事務(wù)邑茄,讓其他的事務(wù)得也執(zhí)行姨蝴,將參數(shù):innodb_deadlock_detect 設(shè)置為 on(默認(rèn)就是on),表示開(kāi)啟這個(gè)邏輯肺缕。
  • 死鎖檢測(cè)
    1.死鎖檢測(cè)比較耗cpu資源左医,它是一個(gè)o(n)的操作授帕,,所以當(dāng)并發(fā)比較大的時(shí)候炒辉,發(fā)現(xiàn)單位時(shí)間內(nèi)執(zhí)行的事務(wù)缺不多豪墅,但是cpu確被打滿,那很有可能是死鎖檢測(cè)耗掉了大量的cpu資源
  • 控制死鎖
    1.減少死鎖的方向是控制相同資源的并發(fā)事務(wù)量黔寇,一種業(yè)務(wù)做法是把資源分散偶器,分散對(duì)相同資源的并發(fā)事務(wù)沖突;

一 鎖類(lèi)型

概括性來(lái)說(shuō)缝裤,mysql innodb存儲(chǔ)引擎有兩種鎖類(lèi)型屏轰,分別是行級(jí)別的行鎖和表級(jí)別的意向鎖;
行鎖有如下兩種類(lèi)型:

  • 行共享鎖(S Lock):允許事務(wù)讀取一行數(shù)據(jù)憋飞;
  • 行排他鎖(X Lock): 允許事務(wù)刪除或是更新一條數(shù)據(jù)霎苗;
    如果一個(gè)事務(wù)想要更新或是刪除一行數(shù)據(jù),就必須獲取這行數(shù)據(jù)的排他鎖榛做;如果已經(jīng)有其他事務(wù)獲取該行的共享鎖唁盏,就會(huì)阻塞其他事務(wù)獲取該行的排他鎖,但是不阻塞獲取共享检眯,行共享和排他鎖的兼容性如下:


    image.png

    為了支持多種粒度的鎖機(jī)制厘擂,innodb也支持表級(jí)別的加鎖,要想獲取細(xì)粒度的鎖(行鎖)锰瘸,就必須先獲取更粗粒度的鎖(意向鎖)刽严,意向鎖有兩種:

  • 意向共享鎖(IS Lock): 事務(wù)想要獲取表中的某行或是某幾行的共享鎖;
  • 意向排他鎖(IX Lock): 事務(wù)想要獲取表中的某行或是某幾行的排他鎖避凝;
    意向鎖和行鎖的兼容性如下圖所示:


    image.png

二 一致性非鎖定讀

一個(gè)事務(wù)想要讀取一行記錄舞萄,需要先獲取這行數(shù)據(jù)的行共享鎖,如果此時(shí)另外一個(gè)事務(wù)先獲取該行的行排他鎖管削,根據(jù)行鎖的兼容性倒脓,后來(lái)的事務(wù)變不能獲取行共享,只能等待行排他鎖釋放含思,這無(wú)疑是不得行了把还,Innodb通過(guò)MVCC機(jī)制實(shí)現(xiàn)了寫(xiě)不阻塞讀,讀取的數(shù)據(jù)如果有其他事務(wù)正在進(jìn)行更新或是刪除操作茸俭,則讀取該行數(shù)據(jù)的上一個(gè)事務(wù)版本號(hào)的數(shù)據(jù),讀取的是一個(gè)快照數(shù)據(jù)安皱,這個(gè)數(shù)據(jù)是通過(guò)undo日志來(lái)獲取的调鬓,undo日志也即是innodb mvcc機(jī)制實(shí)現(xiàn)的根本;

三 一致性鎖定讀

在默認(rèn)的可重復(fù)讀隔離級(jí)別酌伊,innodb讀取數(shù)據(jù)是一致性非鎖定讀腾窝,讀不加鎖缀踪,寫(xiě)不阻塞讀;但是有些業(yè)務(wù)場(chǎng)景需要我們讀取數(shù)據(jù)時(shí)手動(dòng)上鎖以保證數(shù)據(jù)的一致性虹脯,有兩種方式手動(dòng)上鎖實(shí)現(xiàn)一致性鎖定讀

  • select ... for update: 給滿足條件的行加上排他鎖驴娃;
  • select ... lock in share mode: 給滿足條件的行加上共享鎖;
    注意:手動(dòng)加鎖需要在一個(gè)事務(wù)中才生效循集,也即:需要手動(dòng)開(kāi)啟一個(gè)事務(wù)唇敞,begin /../ commit

四 鎖算法

innodb有三種鎖算法,分別是:

  • Record Lock: 所有當(dāng)前記錄
  • Gap Lock: 間隙鎖咒彤,鎖定一個(gè)范圍疆柔,但是不包括記錄本身,例如:(-∞镶柱,1)(1旷档, 5)(5,+ ∞)
  • Next-Key Lock: Record Lock+Gap Lock歇拆, 同樣鎖定一個(gè)范圍鞋屈,但是包括記錄本身,例如:(-∞故觅,1](1厂庇, 5](5,+ ∞)

規(guī)則:

  • innodb的Record Lock是根據(jù)索引項(xiàng)來(lái)加鎖的逻卖,如果查詢(xún)條件不是根據(jù)索引項(xiàng)來(lái)查詢(xún)宋列,會(huì)鎖定整張表記錄
    說(shuō)明:例如:如果在一個(gè)事務(wù)中執(zhí)行:select * from t1 where id=4 for update; 其中id并沒(méi)有設(shè)置為主鍵,也沒(méi)有添加任何索引评也,則此時(shí)會(huì)阻塞其他事務(wù)的任何插入 更新 刪除操作炼杖;
  • InnoDB通過(guò)索引來(lái)實(shí)現(xiàn)行鎖,而不是通過(guò)鎖住記錄盗迟。因此坤邪,當(dāng)操作的兩條不同記錄擁有相同的索引時(shí),也會(huì)因?yàn)樾墟i被鎖而發(fā)生等待罚缕。
  • 由于InnoDB的索引機(jī)制艇纺,數(shù)據(jù)庫(kù)操作使用了主鍵索引,InnoDB會(huì)鎖住主鍵索引邮弹;使用非主鍵索引時(shí)黔衡,InnoDB會(huì)先鎖住非主鍵索引,再鎖定主鍵索引腌乡。
  • 當(dāng)查詢(xún)的索引是唯一索引時(shí)盟劫,InnoDB存儲(chǔ)引擎會(huì)將Next-Key Lock降級(jí)為Record Lock,即只鎖住索引本身与纽,而不是范圍侣签。
  • InnoDB對(duì)于輔助索引有特殊的處理塘装,不僅會(huì)鎖住輔助索引值所在的范圍,還會(huì)將其下一鍵值加上Gap LOCK影所。
    說(shuō)明:例如:如果某個(gè)列有1蹦肴,3,5三個(gè)索引值猴娩,如果在一個(gè)事務(wù)中執(zhí)行:select * from t1 where id=3 for update時(shí)會(huì)同時(shí)鎖住(1,3]和(3,5)兩個(gè)區(qū)間阴幌,其他事務(wù)如果插入這個(gè)兩個(gè)區(qū)間的值是不得行的,會(huì)阻塞胀溺,但是插入非這連個(gè)區(qū)間是可以的裂七,比如插入:insert into t1 values(7)
  • InnoDB使用Next-Key Lock機(jī)制來(lái)避免Phantom Problem(幻讀問(wèn)題)。
    說(shuō)明:個(gè)人理解在可重復(fù)讀隔離級(jí)別下仓坞,Innodb應(yīng)該是通過(guò)Next-Key Lock機(jī)制+MVCC機(jī)制共同保證不會(huì)發(fā)生幻讀問(wèn)題, MVCC不能完全解決幻讀問(wèn)題背零,MVCC可以解決快照讀問(wèn)題,但是當(dāng)前讀問(wèn)題不能解決无埃,舉例說(shuō)明如下:
    1 MVCC能解決快照度的幻讀問(wèn)題
    例子1
創(chuàng)建表t2
CREATE TABLE `t2` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(20) DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB

開(kāi)啟兩個(gè)事務(wù)tx1和tx2徙瓶,先在tx1事務(wù)中查詢(xún)

mysql> begin;
mysql> select * from t2 where id>5;
+------+------+
| id   | name |
+------+------+
|    6 | dd   |
|    8 | dd   |
|    7 | dd   |
|    9 | rr   |
|   10 | re   |
+------+------+
5 rows in set (0.00 sec)

然后事務(wù)2中,插入一行記錄嫉称,并提交

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t2 values(12,"rr");
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

結(jié)論:
再在事務(wù)一查詢(xún)相同語(yǔ)句侦镇,查詢(xún)不到12這條記錄,因?yàn)槠胀ǖ膕elect是快照讀织阅,快照讀根據(jù)MVCC機(jī)制不會(huì)讀到大于當(dāng)前事務(wù)版本的數(shù)據(jù)壳繁,所以MVCC可以解決快照讀的幻讀問(wèn)題

2 MVCC不能解決當(dāng)前讀的幻讀問(wèn)題,當(dāng)前讀是讀取最新的數(shù)據(jù)荔棉,更新刪除等就是當(dāng)前讀
例子2:

  • 事務(wù)1執(zhí)行以下語(yǔ)句闹炉,for update
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t2 where id>5 for update;
+------+------+
| id   | name |
+------+------+
|    6 | dd   |
|    8 | dd   |
|    7 | dd   |
|    9 | rr   |
|   10 | re   |
|   12 | rr   |
|   13 | rr   |
+------+------+
7 rows in set (0.00 sec)
  • 然后再事務(wù)2中執(zhí)行,插入14語(yǔ)句
mysql> begin;
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t2 values(14,"rr");

結(jié)論:
發(fā)現(xiàn)事務(wù)2進(jìn)行鎖等待润樱,不能插入渣触,那是因?yàn)槭聞?wù)1中for update對(duì)加了next-key lock,對(duì)區(qū)間(5,+∞)進(jìn)行了加鎖壹若,導(dǎo)致這個(gè)區(qū)間的插入操作都等待鎖嗅钻,所以next-key lock能解決到一些幻讀問(wèn)題

例子3
先在事務(wù)1執(zhí)行下面操作

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t2;
+------+------+
| id   | name |
+------+------+
|    1 | dd3  |
|    2 | dd3  |
|    3 | dd   |
|    4 | dd   |
|    6 | dd   |
|    8 | dd   |
|    7 | dd   |
|    9 | rr   |
|   10 | re   |
|   12 | rr   |
|   13 | rr   |
+------+------+
11 rows in set (0.00 sec)

此時(shí)事務(wù)一種查詢(xún)到11條數(shù)據(jù),事務(wù)一不提交店展,然后開(kāi)啟事務(wù)2养篓,在事務(wù)2中執(zhí)行一個(gè)插入操作,并commit

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t2 values(14, "22");
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

然后我們?cè)僭谑聞?wù)1中執(zhí)行更新操作,然后相同的查詢(xún)

mysql> update t2 set name='aa';
Query OK, 12 rows affected (11.66 sec)
Rows matched: 12  Changed: 12  Warnings: 0

mysql> select * from t2;
+------+------+
| id   | name |
+------+------+
|    1 | aa   |
|    2 | aa   |
|    3 | aa   |
|    4 | aa   |
|    6 | aa   |
|    8 | aa   |
|    7 | aa   |
|    9 | aa   |
|   10 | aa   |
|   12 | aa   |
|   13 | aa   |
|   14 | aa   |
+------+------+
12 rows in set (0.00 sec)

結(jié)論:
我們發(fā)現(xiàn)在事務(wù)一中讀取到了事務(wù)二插入的數(shù)據(jù)赂蕴,在同一個(gè)事務(wù)中兩次讀取的數(shù)據(jù)不一致觉至,發(fā)生了幻讀,原因在于發(fā)生了一次當(dāng)前讀(更新操作)睡腿,所以此時(shí)MVCC沒(méi)有解決到幻讀問(wèn)題
通過(guò)例子1 2 3我們得出最終結(jié)論:

  • 在可重復(fù)讀隔離級(jí)別下语御,MVCC機(jī)制可以解決快照讀的幻讀問(wèn)題,但是如果有當(dāng)前讀席怪,那就有可能發(fā)生幻讀了
  • 如果有當(dāng)前讀应闯,想要預(yù)防幻讀,可以通過(guò)加行鎖挂捻,通過(guò)Next-Key Lock算法機(jī)制保證在記錄周?chē)秶苌湘i防止幻讀問(wèn)題

引用:
《MYSQL技術(shù)內(nèi)幕 Innodb存儲(chǔ)引擎》
《丁奇45講》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碉纺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子刻撒,更是在濱河造成了極大的恐慌骨田,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件声怔,死亡現(xiàn)場(chǎng)離奇詭異态贤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)醋火,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)悠汽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人芥驳,你說(shuō)我怎么就攤上這事柿冲。” “怎么了兆旬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵假抄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我丽猬,道長(zhǎng)宿饱,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任宝鼓,我火速辦了婚禮刑棵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘愚铡。我一直安慰自己蛉签,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布沥寥。 她就那樣靜靜地躺著掏颊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪作箍。 梳的紋絲不亂的頭發(fā)上患雇,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音淮野,去河邊找鬼捧书。 笑死吹泡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的经瓷。 我是一名探鬼主播爆哑,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼舆吮!你這毒婦竟也來(lái)了揭朝?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤色冀,失蹤者是張志新(化名)和其女友劉穎潭袱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體锋恬,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡屯换,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了伶氢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片趟径。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖癣防,靈堂內(nèi)的尸體忽然破棺而出蜗巧,到底是詐尸還是另有隱情,我是刑警寧澤蕾盯,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布幕屹,位于F島的核電站,受9級(jí)特大地震影響级遭,放射性物質(zhì)發(fā)生泄漏望拖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一挫鸽、第九天 我趴在偏房一處隱蔽的房頂上張望说敏。 院中可真熱鬧,春花似錦丢郊、人聲如沸盔沫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)架诞。三九已至,卻和暖如春干茉,著一層夾襖步出監(jiān)牢的瞬間谴忧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留沾谓,地道東北人委造。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像均驶,于是被迫代替她去往敵國(guó)和親争涌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355