MySQL中的鎖1-基本概念

什么是鎖

在對共享資源并發(fā)訪問時翅溺,鎖用來保障數據的準確。通俗點理解,鎖就類似于排隊飞蚓,Java中synchronized鎖是在對象頭上進行排隊,分布式鎖是在一個公用的存儲服務上排隊拴鸵,而數據庫中的鎖是在所操作記錄的對象上排隊玷坠。

MySQL中鎖的類型

各大主流數據庫都會有鎖的實現,而鎖正是數據庫區(qū)別于文件系統(tǒng)的特性之一劲藐。不僅不同數據庫之間鎖的實現不同八堡,MySQL中不同存儲引擎對于鎖的實現也各不相同。

大體而言MySQL數據庫中既有表鎖聘芜,又有行鎖兄渺。在Innodb存儲引擎中會使用到下列這些鎖:

  • Shared and Exclusive Lock
  • Intention Lock
  • Record Lock
  • Gap Lock
  • Next-Key Lock
  • Insert Intention Lock
  • AUTO-INC Locks

MyISAM中實現的鎖是表鎖,并發(fā)情況下的讀沒有問題汰现,但是并發(fā)插入的性能很差挂谍。InnoDB實現的是行鎖,鎖定粒度小并發(fā)度高瞎饲。MySQL默認的存儲引擎是InnoDB口叙,且官方目前打算不再繼續(xù)對其他存儲進行開發(fā)維護,所以這里我們討論的鎖都是基于InnoDB存儲引擎嗅战。

鎖都是鎖在索引上的妄田,無論是聚集索引(主鍵)還是二級索引

在InnoDB中行鎖的模式有兩種:

  • 共享鎖(S Lock),允許事務讀取一行數據驮捍。
  • 排他鎖(X Lock)疟呐,允許事務刪除或者更新一行數據。

意向鎖

除了行級別的鎖东且,InnoDB中還支持表級別的鎖启具。為了實現多粒度的鎖(多粒度的鎖表示在數據庫中不但能實現行級別的鎖,還可以實現頁級別的鎖珊泳,表級別的鎖甚至數據庫級別的鎖)鲁冯,InnoDB還支持另外一種鎖的模式,意向鎖色查。意向鎖主要是為了在一個事務中揭示下一行將被請求的鎖類型晓褪。InnoDB同樣支持兩種意向鎖:

  • 意向共享鎖(IS Lock),事務想要獲取表中某幾行的共享鎖综慎。
  • 意向排他鎖(IX Lock),事務想要獲取表中某幾行的排他鎖勤庐。

意向鎖的工作方式



MySQL加鎖的方式是從上往下一層層加的示惊。如果事務A要在記錄1上加一把X鎖好港,則步驟如下:

  1. 在記錄1所在的數據庫上加一把意向鎖IX;
  2. 在記錄1所在的表上加一把意向鎖IX;
  3. 在記錄1所在的頁上加一把意向鎖IX米罚;
  4. 在記錄1上加一把X鎖钧汹。

InnoDB沒有數據庫級別的鎖,也沒有頁級別的鎖录择,InnoDB只能在表和記錄上加鎖拔莱,所以InnoDB的意向鎖只能加在表上,即InnoDB中的意向鎖都是表鎖隘竭。

下面來看看共享鎖塘秦、排他鎖、意向共享鎖动看、意向排他鎖的兼容性


InnoDB中鎖的兼容性

加鎖以及查看

加鎖

針對某條記錄的修改和刪除會隱式的加一把X鎖尊剔,如果正對查詢也想要加鎖就需要在SQL語句中顯示的指定。

查詢操作通過在SQL語句的末尾處增加for update來加X鎖
select * from t1 where a=1 for update;

查詢操作通過在SQL語句的末尾處增加lock in share mode來加S鎖
select * from t1 where a=1 lock in share mode;

鎖超時

當產生鎖競爭時菱皆,如果持有鎖的一方遲遲不釋放鎖须误,這時請求鎖的事務(或session)會一直等待鎖的釋放。但是這個等待鎖的過程是有等待超時的仇轻,通過innodb_lock_wait_timeout變量進行設置京痢,默認50s。也就是說等待50秒后還沒有獲取到鎖就放棄等待篷店,同時拋出錯誤ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

鎖等待超時

查看

可以通過show engine innodb status\G;指令來查看加鎖的情況祭椰,該指令會顯示很多和innodb存儲引擎相關的運行信息,其中TRANSACTIONS表示和鎖相關的信息船庇。默認顯示的情況如下:

如果想要顯示更詳細的信息吭产,可以將innodb_status_output_locks參數打開,在MySQL5.7中其默認是關閉的鸭轮。

打開之后我們可以看到關于鎖更詳細的信息

-- Record lock : 表示是鎖住的記錄
-- heap no 2 PHYSICAL RECORD: n_fields 5 : 表示鎖住記錄的heap no 為2的物理記錄臣淤,由5個列組成
-- compact format : 表示這條記錄存儲的格式(Dynamic其實也是compact的格式)
-- info bits : 0 -- 表示這條記錄沒有被刪除; 非0 -- 表示被修改或者被刪除(32)

在MySQL5.7之后的版本中,我們可以通過sys庫下的innodb_lock_waits表來查看更詳細的信息窃爷,注意只有當產生了鎖等待時該表中才會有記錄邑蒋。

select * from innodb_lock_waits\G;
*************************** 1. row ***************************
                wait_started: 2018-07-15 12:06:27   -- 開始的時間
                    wait_age: 00:00:09          -- 等待的時間                    
               wait_age_secs: 9             -- 等待的秒數
                locked_table: `test`.`t1`           -- 鎖主的表(意向鎖)
                locked_index: GEN_CLUST_INDEX       -- 鎖住的是系統(tǒng)生成的聚集索引,鎖都是在索引上的
                 locked_type: RECORD            -- 鎖的類型按厘,記錄鎖
              waiting_trx_id: 421992807332576       -- 等待鎖的事務ID
         waiting_trx_started: 2018-07-15 12:06:27
             waiting_trx_age: 00:00:09
     waiting_trx_rows_locked: 1
   waiting_trx_rows_modified: 0
                 waiting_pid: 13
               waiting_query: select * from t1 where a=2 lock in share mode -- 等待鎖的SQL語句
             waiting_lock_id: 421992807332576:25:3:2   -- 事務ID:space:page_no:heap_no
           waiting_lock_mode: S                        -- 等待的鎖的模式
             blocking_trx_id: 3338                     
                blocking_pid: 12
              blocking_query: NULL
            blocking_lock_id: 3338:25:3:2
          blocking_lock_mode: X                -- 阻塞的鎖的類型
        blocking_trx_started: 2018-07-15 12:04:41
            blocking_trx_age: 00:01:55
    blocking_trx_rows_locked: 2
  blocking_trx_rows_modified: 0
     sql_kill_blocking_query: KILL QUERY 12
sql_kill_blocking_connection: KILL 12                  -- 給出了建議
1 row in set, 3 warnings (0.00 sec)

下面列舉一下通過show engine innodb status\G指令看到的各種鎖的樣子医吊。

1. 意向鎖
TABLE LOCK table `test`.`t3` trx id 3962 lock mode IX

2. Record Locks
RECORD LOCKS space id 39 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 3962 lock_mode X locks rec but not gap
2.1 從index PRIMARY可以看出該鎖加在主鍵上
2.2 記錄鎖除了lock_mode X locks rec but not gap還有l(wèi)ock_mode S locks rec but not gap

3. Gap Locks
RECORD LOCKS space id 39 page no 5 n bits 72 index c of table `test`.`t3` trx id 3962 lock_mode X locks gap before rec

4. Next-Key Locks
RECORD LOCKS space id 39 page no 5 n bits 72 index c of table `test`.`t3` trx id 3962 lock_mode X

5. Insert Intention Locks
RECORD LOCKS space id 279 page no 3 n bits 72 index PRIMARY of table `test`.`t3` trx id 133587907 lock_mode X insert intention waiting

6. AUTO-INC Locks
TABLE LOCK table xx trx id 7498948 lock mode AUTO-INC waiting

讀與MVCC

我們知道如果某行數據加了X鎖, 就沒法加S鎖逮京,即沒法讀了卿堂,不過在實際情況中一般數據庫中都允許并發(fā)讀的,即使要讀取的記錄上存在X鎖。普通的讀操作(非for updatelock in share mode)不會加鎖草描。那么在MySQL中如何保障存在DDL的并發(fā)操作中讀的一致性呢览绿?Innodb使用了MVCC技術來保證讀的一致性

MVCC (Multiversion Concurrency Control)穗慕,即多版本并發(fā)控制技術,它使得大部分支持行鎖的事務引擎饿敲,不再單純的使用行鎖來進行數據庫的并發(fā)控制,取而代之的是把數據庫的行鎖與行的多個版本結合起來逛绵,只需要很小的開銷,就可以實現非鎖定讀怀各,從而大大提高數據庫系統(tǒng)的并發(fā)性能


如果要讀取的行上存在X鎖,這時讀操作不會等行上X鎖的釋放术浪,而是去讀取行的一個快照版本瓢对。由于沒有事務會對快照數據進行修改,所以對于快照的讀取是不用上鎖的添吗。

read committedrepeatable read的事務隔離級別中沥曹,都是使用MVCC進行讀操作。不過這兩種隔離級別在選擇哪個快照版本進行讀取問題上存在區(qū)別碟联,區(qū)別如下:

  • read committed選擇最新的快照版本進行讀(事務A)妓美,如果其他事務(事務B)對要讀取的行進行了更新并提交。則在事務A再進行讀時讀取到的數據版本是事務B提交修改后形成的最新快照版本鲤孵。
  • repeatable read讀取的是事務(事務A)一開始時記錄的快照版本壶栋,即使后面事務B對數據進行了修改并提交,只要事務A沒有提交普监,那么在事務A中讀取的版本依然是一開始的快照版本贵试。

這也就能說明為啥在read committed中存在不可重復讀現象,而repeatable read不存在凯正。

MVCC實現讀是不需要加鎖的毙玻,MySQL當中除了MVCC的方式之外,我們還可以通過顯示的加鎖來保證并發(fā)過程中數據讀取的一致性廊散∩L玻可以通過下面兩種方式顯式的加鎖:

  1. select ... for update; 加X鎖
  2. select ... lock in share mode; 加S鎖

這兩種形式的查詢語句要放在事務當中,一旦事務提交了允睹,鎖也就釋放了运准。

?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市缭受,隨后出現的幾起案子胁澳,更是在濱河造成了極大的恐慌,老刑警劉巖米者,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件韭畸,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機胰丁,發(fā)現死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門普筹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人隘马,你說我怎么就攤上這事∑薅ィ” “怎么了酸员?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長讳嘱。 經常有香客問我幔嗦,道長,這世上最難降的妖魔是什么沥潭? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任邀泉,我火速辦了婚禮,結果婚禮上钝鸽,老公的妹妹穿的比我還像新娘汇恤。我一直安慰自己,他們只是感情好拔恰,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布因谎。 她就那樣靜靜地躺著,像睡著了一般颜懊。 火紅的嫁衣襯著肌膚如雪财岔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天河爹,我揣著相機與錄音匠璧,去河邊找鬼。 笑死咸这,一個胖子當著我的面吹牛夷恍,可吹牛的內容都是我干的。 我是一名探鬼主播炊苫,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼裁厅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了侨艾?” 一聲冷哼從身側響起执虹,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎唠梨,沒想到半個月后袋励,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年茬故,在試婚紗的時候發(fā)現自己被綠了盖灸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡磺芭,死狀恐怖赁炎,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情钾腺,我是刑警寧澤徙垫,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站放棒,受9級特大地震影響姻报,放射性物質發(fā)生泄漏。R本人自食惡果不足惜间螟,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一吴旋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧厢破,春花似錦荣瑟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至加勤,卻和暖如春仙辟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鳄梅。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工叠国, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人戴尸。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓粟焊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親孙蒙。 傳聞我的和親對象是個殘疾皇子项棠,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內容