使用mysql中的鎖解決高并發(fā)問題

阿里云產(chǎn)品通用代金券,最高可領(lǐng)1888分享一波阿里云紅包. 阿里云的購(gòu)買入口

為什么要加鎖

多核計(jì)算機(jī)的出現(xiàn),計(jì)算機(jī)實(shí)現(xiàn)真正并行計(jì)算,可以在同一時(shí)刻,執(zhí)行多個(gè)任務(wù)伶氢。在多線程編程中,因?yàn)榫€程執(zhí)行順序不可控導(dǎo)致的數(shù)據(jù)錯(cuò)誤瘪吏。比如癣防,多線程的理想狀態(tài)是這樣的
多線程理想.jpg

但是實(shí)際情況是這樣的:


多線程實(shí)際.jpg

在網(wǎng)絡(luò)編程中,在同一時(shí)刻肪虎,多個(gè)客戶端同時(shí)請(qǐng)求同一個(gè)資源劣砍,如果不做控制,也會(huì)帶來數(shù)據(jù)錯(cuò)誤扇救。比如在同一時(shí)間有10000人去搶10張火車票刑枝,10張火車票有可能會(huì)買給100個(gè)人,這顯然是不符合要求的迅腔。
在多線程編程中,為了解決線程執(zhí)行不可控帶來的問題,通常情況下都是通過加鎖來實(shí)現(xiàn)數(shù)據(jù)同步的装畅。在網(wǎng)絡(luò)編程中,也可以通過加鎖機(jī)制來控制沧烈。

在網(wǎng)絡(luò)編程中掠兄,可以通過給數(shù)據(jù)庫(kù)加鎖,達(dá)到控制并發(fā)的目的。在php開發(fā)時(shí)蚂夕,基本都是使用mysql作為數(shù)據(jù)庫(kù)迅诬。所以,就會(huì)給mysql加鎖控制網(wǎng)絡(luò)并發(fā)引起數(shù)據(jù)錯(cuò)誤問題婿牍。

MySQL的存儲(chǔ)引擎

不是要說MySQL的鎖嗎,怎么說上存儲(chǔ)引擎了?因?yàn)镸ySQL存儲(chǔ)引擎不同,鎖也會(huì)不同侈贷。MySQL有MyISAMInnoDB兩種存儲(chǔ)引擎,現(xiàn)在主要使用InnoDB,所以主要介紹InnoDB下鎖的使用等脂。

InnoDB引擎支持事務(wù)操作俏蛮,使用事務(wù)可以保證多條sql語(yǔ)句執(zhí)行的完整性(要不都成功,要不都失敗)

事務(wù)是由一組SQL語(yǔ)句組成的邏輯處理單元,事務(wù)具有4屬性
  • 原子性(Actomicity):事務(wù)是一個(gè)原子操作單元上遥,其對(duì)數(shù)據(jù)的修改搏屑,要么全都執(zhí)行,要么全都不執(zhí)行粉楚。
  • 一致性(Consistent):在事務(wù)開始和完成時(shí)辣恋,數(shù)據(jù)都必須保持一致狀態(tài)。這意味著所有相關(guān)的數(shù)據(jù)規(guī)則都必須應(yīng)用于事務(wù)的修改解幼,以操持完整性抑党;事務(wù)結(jié)束時(shí),所有的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如B樹索引或雙向鏈表)也都必須是正確的撵摆。
  • 隔離性(Isolation):數(shù)據(jù)庫(kù)系統(tǒng)提供一定的隔離機(jī)制底靠,保證事務(wù)在不受外部并發(fā)操作影響的“獨(dú)立”環(huán)境執(zhí)行。這意味著事務(wù)處理過程中的中間狀態(tài)對(duì)外部是不可見的特铝,反之亦然暑中。
  • 持久性(Durable):事務(wù)完成之后,它對(duì)于數(shù)據(jù)的修改是永久性的鲫剿,即使出現(xiàn)系統(tǒng)故障也能夠保持鳄逾。
多個(gè)事務(wù)并發(fā)執(zhí)行會(huì)帶來新的問題
  • 更新丟失(Lost Update):當(dāng)兩個(gè)或多個(gè)事務(wù)選擇同一行,然后基于最初選定的值更新該行時(shí)灵莲,由于每個(gè) 事務(wù)都不知道其他事務(wù)的存在雕凹,就會(huì)發(fā)生丟失更新問題——最后的更新覆蓋了其他事務(wù)所做的更新。例如政冻,兩個(gè)編輯人員制作了同一文檔的電子副本枚抵。每個(gè)編輯人員獨(dú)立地更改其副本,然后保存更改后的副本明场,這樣就覆蓋了原始文檔汽摹。最后保存其更改保存其更改副本的編輯人員覆蓋另一個(gè)編輯人員所做的修改。如果在一個(gè)編輯人員完成并提交事務(wù)之前苦锨,另一個(gè)編輯人員不能訪問同一文件逼泣,則可避免此問題
  • 臟讀(Dirty Reads):一個(gè)事務(wù)正在對(duì)一條記錄做修改趴泌,在這個(gè)事務(wù)并提交前,這條記錄的數(shù)據(jù)就處于不一致狀態(tài)拉庶;這時(shí)嗜憔,另一個(gè)事務(wù)也來讀取同一條記錄,如果不加控制砍的,第二個(gè)事務(wù)讀取了這些“臟”的數(shù)據(jù)痹筛,并據(jù)此做進(jìn)一步的處理,就會(huì)產(chǎn)生未提交的數(shù)據(jù)依賴關(guān)系廓鞠。這種現(xiàn)象被形象地叫做“臟讀”。
  • 不可重復(fù)讀(Non-Repeatable Reads):一個(gè)事務(wù)在讀取某些數(shù)據(jù)已經(jīng)發(fā)生了改變谣旁、或某些記錄已經(jīng)被刪除了床佳!這種現(xiàn)象叫做“不可重復(fù)讀”。
  • 幻讀(Phantom Reads):一個(gè)事務(wù)按相同的查詢條件重新讀取以前檢索過的數(shù)據(jù)榄审,卻發(fā)現(xiàn)其他事務(wù)插入了滿足其查詢條件的新數(shù)據(jù)砌们,這種現(xiàn)象就稱為“幻讀”。

曾經(jīng)年少無(wú)知的我,以為使用事務(wù)就能保證并發(fā)情況下數(shù)據(jù)同步問題,后來的一次慘痛經(jīng)歷才明白了,事務(wù)不能保證并發(fā)情況的數(shù)據(jù)同步問題,需要事務(wù)和鎖同時(shí)使用才能保證搁进。

鎖的種類

  • 樂觀鎖 機(jī)制采取了更加寬松的加鎖機(jī)制浪感。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫(kù)的鎖機(jī)制實(shí)現(xiàn),以保證操作最大程度的獨(dú)占性饼问。但隨之而來的就是數(shù)據(jù)庫(kù)性能的大量開銷影兽,特別是對(duì)長(zhǎng)事務(wù)而言,這樣的開銷往往無(wú)法承受莱革。相對(duì)悲觀鎖而言峻堰,樂觀鎖更傾向于開發(fā)運(yùn)用。
  • 悲觀鎖 具有強(qiáng)烈的獨(dú)占和排他特性盅视。它指的是對(duì)數(shù)據(jù)被外界(包括本系統(tǒng)當(dāng)前的其他事務(wù)捐名,以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此闹击,在整個(gè)數(shù)據(jù)處理過程中镶蹋,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實(shí)現(xiàn)赏半,往往依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制(也只有數(shù)據(jù)庫(kù)層提供的鎖機(jī)制才能真正保證數(shù)據(jù)訪問的排他性贺归,否則,即使在本系統(tǒng)中實(shí)現(xiàn)了加鎖機(jī)制除破,也無(wú)法保證外部系統(tǒng)不會(huì)修改數(shù)據(jù))牧氮。

MySQL中鎖的種類

樂觀鎖和悲觀鎖是一種思想,不是具體實(shí)現(xiàn),在MySQL中,有鎖的具體的實(shí)現(xiàn)方式
(文中的線程在MySQL中可以視作MySQL的連接)

  • 共享鎖 一個(gè)線程在持有鎖時(shí),其他的線程可以查詢被鎖的數(shù)據(jù),但是不能修改,不能刪除。實(shí)現(xiàn)方式
    SELECT * FROM table_name WHERE id =? lock in share mode;
  • 排它鎖 一個(gè)線程在持有鎖時(shí),其他的線程不能查詢,不能更新,不能刪除被鎖的數(shù)據(jù),直到鎖被釋放.
    SELECT * FROM table_name WHERE id =? for update
  • 總結(jié)一下:共享鎖類似于java中的讀鎖,一個(gè)線程在持有樂觀鎖的時(shí)候,其他的線程也可以對(duì)被鎖的數(shù)據(jù)進(jìn)行讀操作,但是不能對(duì)被鎖的數(shù)據(jù)進(jìn)行刪除和更新操作;排他鎖類似于java的寫鎖,一個(gè)線程持有寫鎖的時(shí)候,其他的線程不能再對(duì)被鎖的數(shù)據(jù)進(jìn)行任何查詢,更新,刪除操作瑰枫。
  • 重點(diǎn) InnoDB的行鎖是基于索引實(shí)現(xiàn)的,如果在查詢中不使用索引,會(huì)鎖表踱葛。

MySQL鎖粒度

  • 表級(jí)鎖 是MySQL中鎖定粒度最大的一種鎖丹莲,表示對(duì)當(dāng)前操作的整張表加鎖,它實(shí)現(xiàn)簡(jiǎn)單尸诽,資源消耗較少甥材,被大部分MySQL引擎支持。最常使用的MyISAM與InnoDB都支持表級(jí)鎖定性含。表級(jí)鎖分為表共享讀鎖與表獨(dú)占寫鎖洲赵。
  • 行級(jí)鎖 是Mysql中鎖定粒度最細(xì)的一種鎖,表示只針對(duì)當(dāng)前操作的行進(jìn)行加鎖商蕴。行級(jí)鎖能大大減少數(shù)據(jù)庫(kù)操作的沖突叠萍。其加鎖粒度最小天吓,但加鎖的開銷也最大咽斧。行級(jí)鎖分為共享鎖 和 排他鎖其馏。

共享鎖的使用

注意: 下面的操作,都是行鎖操作,MySQL為InnoDB引擎,id為自增主鍵

先創(chuàng)建一個(gè)測(cè)試表

CREATE TABLE `test`  (
  `id` int(0) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `number` bigint(0) NOT NULL,
  `age` int(0) NULL,
  PRIMARY KEY (`id`)
) ENGINE = InnoDB;

看一下隨便插入的幾條數(shù)據(jù)


沒有問題,使用共享鎖看一下效果:

  1. 開啟事務(wù) begin;
  2. 給id為1的數(shù)據(jù)加共享鎖 mysql> select * from test where id=1 lock in share mode;
  3. 分別使用加鎖和不加鎖查詢id為1 的數(shù)據(jù)



    都可以查詢到數(shù)據(jù)

修改id為1 的數(shù)據(jù)看看



sql語(yǔ)句會(huì)一直停在這里,直到超時(shí)或者鎖釋放(事務(wù)提交或者回滾)



左邊的事務(wù)提交后,右邊的sql會(huì)執(zhí)行,完成更新操作拆宛。

同樣,刪除操作也會(huì)等待鎖釋放才能操作,這里就不演示了茂嗓。


再看一下另一種情況,左邊鎖住id為5的數(shù)據(jù),右邊更新id為1 的數(shù)據(jù),不受影響缠劝。這就是行級(jí)鎖舷蒲,只會(huì)鎖住相關(guān)的一行數(shù)據(jù)


排他鎖的使用

還是使用test這張表

  1. 開啟事務(wù)begin;
  2. 給id1的數(shù)據(jù)加排他鎖select * from test where id = 1 for update;
  3. 在右邊查詢id為1的數(shù)據(jù)



    查詢語(yǔ)句會(huì)一直等待,直到超時(shí)或者鎖釋放(左邊commit或者rollback)


左邊commit后



使用排它鎖對(duì)id為5的數(shù)據(jù)加鎖后,更新id為5的數(shù)據(jù)



sql語(yǔ)句同樣會(huì)等待,直到超時(shí)或者鎖釋放,刪除操作也是一樣

看一下對(duì)id為1的數(shù)據(jù)加鎖,然后操作id不為1的數(shù)據(jù)的情況



沒有問題,MySQL只是鎖住了id為5的數(shù)據(jù),其他的數(shù)據(jù)都可以操作蹬昌。

看一下InnoDB引擎鎖表的情況


我們常常說InnoDB是行鎖例书,但是這里介紹一下它鎖表的情況锣尉。因?yàn)閚ame列沒有索引,所以,在加行鎖的時(shí)候,MySQL不能加正常加行鎖,會(huì)鎖住整張表。
InnoDB行鎖是通過索引上的索引項(xiàng)來實(shí)現(xiàn)的决采,這一點(diǎn)MySQL與Oracle不同自沧,后者是通過在數(shù)據(jù)中對(duì)相應(yīng)數(shù)據(jù)行加鎖來實(shí)現(xiàn)的。InnoDB這種行鎖實(shí)現(xiàn)特點(diǎn)意味者:只有通過索引條件檢索數(shù)據(jù)织狐,InnoDB才會(huì)使用行級(jí)鎖暂幼,否則,InnoDB將使用表鎖移迫!
在實(shí)際應(yīng)用中旺嬉,要特別注意InnoDB行鎖的這一特性,不然的話厨埋,可能導(dǎo)致大量的鎖沖突邪媳,從而影響并發(fā)性能。

再看另一種情況


使用排它鎖對(duì)id為1的數(shù)據(jù)加鎖時(shí),使用不加鎖的查詢和沒有約束的查詢時(shí),一樣可以立刻查詢到數(shù)據(jù)荡陷。只有使用加鎖的查詢或者更新和刪除時(shí)才會(huì)等待鎖釋放雨效。

總結(jié)

  • InnoDB的鎖配合事務(wù)使用
  • MySQL有共享鎖和排它鎖
  • 使用共享鎖時(shí),其他線程(連接)可以查詢數(shù)據(jù),但是不能更新和刪除數(shù)據(jù),使用排它鎖時(shí),不能查詢數(shù)據(jù)不能更新數(shù)據(jù),不能刪除數(shù)據(jù)
  • MySQL的InnoDB引擎支持行級(jí)鎖和表級(jí)鎖,行級(jí)鎖
  • InnoDB的行級(jí)鎖是基于索引的,加鎖是對(duì)索引加鎖,加鎖時(shí)沒有索引時(shí)會(huì)鎖住整張表

以上是我對(duì)MySQL鎖的理解,文中如果有不正確的地方,還請(qǐng)各位大哥批評(píng)指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末废赞,一起剝皮案震驚了整個(gè)濱河市徽龟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌唉地,老刑警劉巖据悔,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件传透,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡极颓,警方通過查閱死者的電腦和手機(jī)朱盐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菠隆,“玉大人兵琳,你說我怎么就攤上這事『Ь叮” “怎么了躯肌?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)破衔。 經(jīng)常有香客問我羡榴,道長(zhǎng),這世上最難降的妖魔是什么运敢? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮忠售,結(jié)果婚禮上传惠,老公的妹妹穿的比我還像新娘。我一直安慰自己稻扬,他們只是感情好卦方,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著泰佳,像睡著了一般盼砍。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上逝她,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天浇坐,我揣著相機(jī)與錄音,去河邊找鬼黔宛。 笑死近刘,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的臀晃。 我是一名探鬼主播觉渴,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼徽惋!你這毒婦竟也來了案淋?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤险绘,失蹤者是張志新(化名)和其女友劉穎踢京,沒想到半個(gè)月后誉碴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡漱挚,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年翔烁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片旨涝。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蹬屹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出白华,到底是詐尸還是另有隱情慨默,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布弧腥,位于F島的核電站厦取,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏管搪。R本人自食惡果不足惜虾攻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望更鲁。 院中可真熱鬧霎箍,春花似錦、人聲如沸澡为。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)媒至。三九已至顶别,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拒啰,已是汗流浹背驯绎。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留图呢,地道東北人条篷。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蛤织,于是被迫代替她去往敵國(guó)和親赴叹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容