MySQL數(shù)據(jù)庫鎖

存在并發(fā)操作的時候喜最,必然需要一種機制來保證數(shù)據(jù)的完整性和一致性偎蘸。鎖就是這樣一種技術實現(xiàn)。

當多個用戶并發(fā)地存取數(shù)據(jù)時,數(shù)據(jù)庫會存在多個事務同時存取同一數(shù)據(jù)的情況迷雪。如果對此不加控制限书,就很有可能會讀取和存儲不正確的數(shù)據(jù),破壞數(shù)據(jù)庫的完整性和一致性章咧。當事務在對某個數(shù)據(jù)進行操作前倦西,先向系統(tǒng)發(fā)出請求,對其加鎖赁严。加鎖后事務就對數(shù)據(jù)對象有了一定的控制扰柠。

在MySQL中存在多種鎖,根據(jù)概念疼约,可分為悲觀鎖和樂觀鎖卤档。

  • 悲觀鎖,也叫悲觀并發(fā)控制程剥,顧名思義就是對事務操作很悲觀劝枣,認為每次拿數(shù)據(jù)都會對數(shù)據(jù)進行修改,因此每次讀取數(shù)據(jù)都會加鎖倡缠。當事務A對某行數(shù)據(jù)應用了鎖哨免,只有當事務A把鎖釋放以后,其他事務才能執(zhí)行與該鎖沖突的操作昙沦,這里的事務A施加的鎖就叫悲觀鎖琢唾。

  • 樂觀鎖,也叫樂觀并發(fā)控制盾饮,顧名思義就是對事務操作比較樂觀采桃,認為多用戶并發(fā)的事務在處理時不會互相影響,各事務能夠在不產(chǎn)生鎖的情況下處理各自影響的那部分數(shù)據(jù)丘损。在提交數(shù)據(jù)更新前普办,每個事務會先檢查在該事務讀取數(shù)據(jù)后,有沒有其他事務又修改了數(shù)據(jù)徘钥。如果有衔蹲,那么當前正在提交的事務會進行回滾。

在MySQL數(shù)據(jù)庫中呈础,悲觀鎖依靠數(shù)據(jù)庫提供的鎖機制來實現(xiàn)的舆驶,樂觀鎖需要使用者自己去實現(xiàn)

從鎖的功能上看而钞,可以分為共享鎖沙廉、排他鎖(獨占鎖)、意向鎖等臼节。共享鎖也稱S鎖撬陵,排他鎖也被稱為X鎖珊皿。

從鎖的粒度來看,又可以分為表鎖巨税、頁鎖蟋定、行鎖。在MySQL中垢夹,最常見的是表鎖和行鎖溢吻。其中MyISAM引擎只有表鎖维费,而InnoDB既有表鎖也有行鎖果元。

表鎖的特點是開銷小,加鎖塊犀盟,不會出現(xiàn)死鎖而晒,鎖定粒度大,發(fā)生鎖沖突的概率最高阅畴,并發(fā)度最低倡怎。相反,行鎖的加鎖開銷比較大贱枣,發(fā)生沖突的概率比較低监署,但是并發(fā)度也高,帶來的副反應就是死鎖纽哥。而頁鎖則界于表鎖和行鎖之間钠乏。

1. MySQL表鎖

MySQL的表鎖有兩種模式:表共享鎖和表獨占鎖。

  • 對于MyISAM的讀操作春塌,不會阻塞其他用戶對同一表的讀請求晓避,但會阻塞對同一表的寫請求;
  • 對于MyISAM的寫操作只壳,則會阻塞其他用戶對于同一表的讀和寫請求俏拱;
  • MyISAM的讀和寫操作之間,以及寫和寫操作之間是串行的吼句。
如何加表鎖

MyISAM表在執(zhí)行查語句之前锅必,會自動給涉及的所有表加讀鎖,在執(zhí)行更新操作(增刪改)前惕艳,會自動給涉及的表加寫鎖搞隐,不需要用戶顯式加鎖。

給MyISAM表顯式加鎖尔艇,一般是為了一定程度模擬事務操作尔许,實現(xiàn)對某一時間點多個表的一致性讀取。比如一個訂單表order有total字段终娃,有訂單明細表order_detail記錄一個訂單多個產(chǎn)品的金額小計money味廊。如果你要判斷這兩個表的金額是否相等,可能需要分別查詢兩個表的金額:

SELECT SUM(`money`) FROM `order_detail`;
SELECT SUM(`total`) FROM `order`;

如果不加鎖,在執(zhí)行一個表的查詢過程中余佛,order_detail表可能已經(jīng)發(fā)生了改變柠新,因此正確的做法是:

LOCK TABLES `order` READ LOCAL,`order_detail` READ LOCAL;
SELECT SUM(`money`) FROM `order_detail`;
SELECT SUM(`total`) FROM `order`;
UNLOCK TABLES;

需要說明的是,在鎖表的同時加了local選項辉巡,其作用就是在滿足MySQL表并發(fā)插入條件的情況下恨憎,允許其他用戶在表尾插入數(shù)據(jù)。

在用LOCK TABLES給表顯示加鎖時郊楣,必須同時取得所有涉及表的鎖憔恳,在執(zhí)行LOCK TABLES后,當前會話只能訪問顯式加鎖的這些表净蚤,不能訪問未加鎖的表钥组;同時,如果加的是讀鎖今瀑,那么只能執(zhí)行查詢操作程梦,而不能操作更新操作,非當前會話可以執(zhí)行UPDATE操作橘荠,但會被阻塞屿附,可以在滿足一定條件時執(zhí)行INSERT操作,不受阻塞哥童。被加鎖的會話不會讀取到其他會話的INSERT數(shù)據(jù)挺份,自動加鎖的情況下也基本如此,這也是MyISAM表不會出現(xiàn)死鎖的原因如蚜。

MyISAM存儲引擎有一個系統(tǒng)變量concurrent_insert压恒,專門用以控制并發(fā)插入行為,因此上述提到的“滿足一定條件”就是:

  • concurrent_insert設置為0時错邦,不允許并發(fā)插入探赫。
  • concurrent_insert設置為1時,如果MyISAM允許線程讀表的同時撬呢,另一個線程從表尾插入記錄伦吠。這是默認設置。
  • concurrent_insert設置為2時魂拦,無論MyISAM有沒有空間毛仪,都允許在表尾插入記錄。

無論是讀鎖還是寫鎖芯勘,兩者的機制和上面提到的差不多箱靴。前面提到,MyISAM表的讀鎖和寫鎖是互斥的荷愕,讀之間是串行的衡怀。

那么如果一個進程請求某個MyISAM表既有讀鎖又有寫鎖時棍矛,MyISAM的默認設置是寫優(yōu)先,可以修改LOW_PRIORITY_UPDATES參數(shù)抛杨,也可以在INSERT够委、UPDATE、DELETE語句中指定LOW_PRIORITY選項來調(diào)節(jié)讀寫鎖的競爭怖现。

另外茁帽,MySQL還提供了一種折中的辦法來調(diào)節(jié)讀寫沖突,即給系統(tǒng)參數(shù)max_write_lock_count設置一個合適的值屈嗤,當一個表的讀鎖達到這個值后潘拨,MySQL暫時將寫請求的優(yōu)先級降低,給讀進程一定獲得鎖的機會恢共。

2. MySQL行鎖

MySQL行鎖主要存在于InnoDB引擎中战秋。InnoDB主要實現(xiàn)了以下兩種類型的行鎖:

  • 共享鎖(S):允許一個事務去讀一行,阻止其他事務獲得相同數(shù)據(jù)集的排他鎖讨韭。
  • 排它鎖(X):允許獲得排他鎖的事務更新數(shù)據(jù),阻塞其他事務取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖癣蟋。

InnoDB還存在一種意向鎖透硝,分為意向共享鎖和意向排他鎖,這兩種鎖都由系統(tǒng)自動添加和自動釋放疯搅,無需人工干預濒生。

依然使用上面的兩張表,把引擎修改為InnoDB幔欧。注意:使用悲觀鎖時罪治,必須關閉MySQL默認開啟的自動提交模式。默認情況下礁蔗,當你執(zhí)行更新操作后觉义,MySQL會立刻將結果進行提交。

讀共享鎖:

SET autocommit = 0;
SELECT `money` FROM `order_detail` WHERE `id` = 2 LOCK IN SHARE MODE;
UPDATE `order_detail` SET `money` = 14 WHERE `id` = 2;
SELECT `money` FROM order_detail WHERE `id` = 2;
COMMIT;

寫排他鎖(獨占鎖):

SET autocommit = 0;
SELECT `money` FROM `order_detail` WHERE `id` = 2 FOR UPDATE;
UPDATE `order_detail` SET `money` = 14 WHERE `id` = 2;

如果事務A先獲得了某行的寫共享鎖浴井,事務B可以獲得該記錄晒骇,但不能對數(shù)據(jù)加寫鎖(可以加S鎖),必須等待事務A提交或回滾后才可以加X鎖磺浙。

需要注意的是洪囤,InnoDB并不總是給數(shù)據(jù)加行鎖,有時候也會加表鎖撕氧。原因在于瘤缩,InnoDB行鎖是通過給索引上的索引項加鎖來實現(xiàn)的。這也意味著只有通過索引條件檢索數(shù)據(jù)伦泥,InnoDB才使用行鎖剥啤,否則將使用表鎖何暮。另外要注意,因為MySQL的行鎖是針對索引加的鎖铐殃,所以雖然可能訪問的是不同的行記錄海洼,但是如果條件中用了相同的索引建,還是會造成鎖沖突富腊。比如order_detail表的order_id是加了索引的坏逢,下面查詢了兩條訂單明細,會出現(xiàn)鎖沖突:

select * from order_detail where order_id = 1 and good_id = 1;
select * from order_detail where order_id = 1 and good_id = 2;

此外赘被,還存在一種“間隙鎖”的概念是整。當我們使用范圍查詢而非相等條件查詢,并請求共享或排他鎖時民假,InnoDB會自動對符合條件的已有數(shù)據(jù)記錄的索引項加鎖浮入,對于鍵值在條件范圍內(nèi)但并不存在的記錄,我們稱之為“間隙”(GAP)羊异,InnoDB也會對這個間隙加鎖事秀,這種機制就是所謂的“間隙鎖”。

InnoDB表大部分情況下都應該使用行鎖野舶,因為事務和行鎖往往就是我們選擇InnoDB表的理由易迹。但個別情況下,我們也可以考慮使用表鎖:

  • InnoDB使用表鎖的情況一:事務需要更新大部分或全部數(shù)據(jù)平道,表又比較大睹欲,如果使用默認的行鎖,效率比較低不說一屋,還可能造成其他事務長時間的等待和鎖沖突窘疮,建議用表鎖提高事務執(zhí)行速度。
  • InnoDB使用表鎖的情況二:事務涉及多個表冀墨,比較復雜闸衫,很可能引起死鎖,造成大量事務回滾轧苫。這種情況可以考慮使用表鎖以避免死鎖楚堤、減少數(shù)據(jù)庫因事務回滾等帶來的開銷。

InnoDB下使用表鎖需要注意以下兩點含懊。

    1. 使用LOCK TABLES雖然也可以加表鎖身冬,但由于表鎖并不是由InnoDB引擎管理,而是由MySQL Server負責的岔乔,因此僅當autocommit = 0酥筝、innodb_table_locks = 1(默認設置)時,InnoDB層才能知道MySQL加的表鎖雏门,MySQL Server也才能感知InnoDB加的行鎖嘿歌。這種情況下顶岸,InnoDB才能自動識別涉及表級鎖的死鎖益眉,否則InnoDB無法自動檢測并處理死鎖。
    1. 在LOCK TABLES對InnoDB表加鎖時要注意將AUTOCOMMIT設為0,否則MySQL不會給表加鎖端逼;在事務結束前笔喉,不要用UNLOCK TABLES釋放表鎖堡僻,因為UNLOCK TABLES會隱式地提交事務观谦;COMMIT或ROLLBACK并不能釋放用LOCK TABLES加的表鎖,必須要用UNLOCK TABLES釋放表鎖靴患。

正確寫法舉例仍侥,寫表t1并從表t2讀:

SET AUTOCOMMIT = 0;
LOCK TABLES t1 WRITE,t2 READ;
-- todo ... [do sth with t1 and t2 here];
COMMIT;
UNLOCK TABLES;
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市鸳君,隨后出現(xiàn)的幾起案子农渊,更是在濱河造成了極大的恐慌,老刑警劉巖或颊,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砸紊,死亡現(xiàn)場離奇詭異,居然都是意外死亡饭宾,警方通過查閱死者的電腦和手機批糟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來看铆,“玉大人,你說我怎么就攤上這事盛末〉耄” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵悄但,是天一觀的道長棠隐。 經(jīng)常有香客問我,道長檐嚣,這世上最難降的妖魔是什么助泽? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮嚎京,結果婚禮上嗡贺,老公的妹妹穿的比我還像新娘。我一直安慰自己鞍帝,他們只是感情好诫睬,可當我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著帕涌,像睡著了一般摄凡。 火紅的嫁衣襯著肌膚如雪续徽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天亲澡,我揣著相機與錄音钦扭,去河邊找鬼。 笑死床绪,一個胖子當著我的面吹牛客情,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播会涎,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼裹匙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了末秃?” 一聲冷哼從身側響起概页,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎练慕,沒想到半個月后惰匙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡铃将,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年项鬼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劲阎。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡绘盟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出悯仙,到底是詐尸還是另有隱情龄毡,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布锡垄,位于F島的核電站沦零,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏货岭。R本人自食惡果不足惜路操,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望千贯。 院中可真熱鬧屯仗,春花似錦、人聲如沸丈牢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽己沛。三九已至慌核,卻和暖如春距境,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背垮卓。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工垫桂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粟按。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓诬滩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親灭将。 傳聞我的和親對象是個殘疾皇子疼鸟,可洞房花燭夜當晚...
    茶點故事閱讀 44,955評論 2 355

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

  • 01概述 數(shù)據(jù)庫事務ACID中的隔離性是通過鎖和MVCC實現(xiàn)的,鎖用于并發(fā)寫操作庙曙,MVCC用于并發(fā)讀操作空镜。因此,數(shù)...
    程序員姜戈閱讀 368評論 0 0
  • 概述 相對其他數(shù)據(jù)庫而言捌朴,MySQL的鎖機制比較簡單吴攒,其最顯著的特點是不同的存儲引擎支持不同的鎖機制。比如砂蔽,MyI...
    湫兮若風__流年閱讀 584評論 0 0
  • 在并發(fā)訪問情況下洼怔,很有可能出現(xiàn)不可重復讀等等讀現(xiàn)象。為了更好的應對高并發(fā)左驾,封鎖镣隶、時間戳、樂觀并發(fā)控制(樂觀鎖)诡右、悲...
    smileNicky閱讀 5,375評論 0 24
  • 1矾缓、為什么要有數(shù)據(jù)庫的鎖機制? 為了解決數(shù)據(jù)庫層面的并發(fā)問題稻爬,多個事務同時修改一份數(shù)據(jù)資源,可能導致臟讀蜕依、不可重復...
    我是一名搬運工閱讀 602評論 0 0
  • 臟讀桅锄、不可重復讀和幻讀都是數(shù)據(jù)庫讀一致性問題,需要由數(shù)據(jù)庫提供一定的事務隔離機制來解決样眠。 (1)鎖機制 解決寫-寫...
    Java耕耘者閱讀 1,471評論 0 1