日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

MySQL - 锁机制初探

發(fā)布時(shí)間:2025/3/21 数据库 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MySQL - 锁机制初探 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 生猛干貨
  • Pre
  • 鎖的分類
  • InnoDB 中的鎖
    • 行鎖
    • InnoDB 行鎖的三種算法實(shí)現(xiàn)
      • Record Lock 鎖
      • Gap Lock 鎖
      • Next-key Lock 鎖
    • 表鎖
      • 表鎖的分類 IS | IX | AUTO-INC Locks
      • InnoDB 自增鎖
  • InnoDB 鎖關(guān)系矩陣
  • InnoDB死鎖問(wèn)題排查思路
    • 基于資源爭(zhēng)用導(dǎo)致死鎖的情況
    • Metadata lock(即元數(shù)據(jù)鎖)導(dǎo)致的死鎖的情況
    • 開發(fā)建議
  • InnoDB 加鎖行為驗(yàn)證
    • 主鍵 + RR
    • 唯一鍵 + RR
    • 非唯一鍵 + RR
    • 無(wú)索引 + RR
  • 搞定MySQL


生猛干貨

帶你搞定MySQL實(shí)戰(zhàn),輕松對(duì)應(yīng)海量業(yè)務(wù)處理及高并發(fā)需求,從容應(yīng)對(duì)大場(chǎng)面試


Pre

MySQL - 解讀MySQL事務(wù)與鎖機(jī)制

MySQL - 共享鎖和排它鎖初探

MySQL - 無(wú)索引行鎖升級(jí)為表鎖

MySQL - 鎖等待及死鎖初探


鎖的分類

在 MySQL 中有三種級(jí)別的鎖:頁(yè)級(jí)鎖、表級(jí)鎖、行級(jí)鎖

  • 表級(jí)鎖:開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。 會(huì)發(fā)生在:MyISAM、memory、InnoDB、BDB 等存儲(chǔ)引擎中
  • 行級(jí)鎖:開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度最高。會(huì)發(fā)生在:InnoDB 存儲(chǔ)引擎
  • 頁(yè)級(jí)鎖:開銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。會(huì)發(fā)生在:BDB 存儲(chǔ)引擎

三種級(jí)別的鎖分別對(duì)應(yīng)存儲(chǔ)引擎關(guān)系如上圖。

Note:MySQL 中的表鎖包括讀鎖和寫鎖


InnoDB 中的鎖

在 MySQL InnoDB 存儲(chǔ)引擎中,鎖分為行鎖和表鎖。

行鎖

其中行鎖包括兩種鎖

  • 共享鎖(S):允許一個(gè)事務(wù)去讀一行,阻止其他事務(wù)獲得相同數(shù)據(jù)集的排他鎖。

  • 排他鎖(X):允許獲得排他鎖的事務(wù)更新數(shù)據(jù),阻止其他事務(wù)取得相同數(shù)據(jù)集的共享讀鎖和排他寫鎖。


InnoDB 行鎖的三種算法實(shí)現(xiàn)

InnoDB 行鎖是通過(guò)對(duì)索引數(shù)據(jù)頁(yè)上的記錄(record)加鎖實(shí)現(xiàn)的。主要實(shí)現(xiàn)算法有 3 種:Record Lock、Gap Lock 和 Next-key Lock。

Record Lock 鎖

  • Record Lock 鎖:單個(gè)行記錄的鎖(鎖數(shù)據(jù),不鎖 Gap)。

Gap Lock 鎖

  • Gap Lock 鎖:間隙鎖,鎖定一個(gè)范圍,不包括記錄本身(不鎖數(shù)據(jù),僅僅鎖數(shù)據(jù)前面的Gap)。

Next-key Lock 鎖

  • Next-key Lock 鎖:同時(shí)鎖住數(shù)據(jù),并且鎖住數(shù)據(jù)前面的 Gap。

表鎖

另外,為了允許行鎖和表鎖共存,實(shí)現(xiàn)多粒度鎖機(jī)制,InnoDB 還有兩種內(nèi)部使用的意向鎖(Intention Locks),這兩種意向鎖都是表鎖。


表鎖的分類 IS | IX | AUTO-INC Locks

表鎖又分為三種

  • 意向共享鎖(IS):事務(wù)計(jì)劃給數(shù)據(jù)行加行共享鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加共享鎖前必須先取得該表的 IS 鎖

  • 意向排他鎖(IX):事務(wù)打算給數(shù)據(jù)行加行排他鎖,事務(wù)在給一個(gè)數(shù)據(jù)行加排他鎖前必須先取得該表的 IX 鎖

  • 自增鎖(AUTO-INC Locks):特殊表鎖,自增長(zhǎng)計(jì)數(shù)器通過(guò)該“鎖”來(lái)獲得子增長(zhǎng)計(jì)數(shù)器最大的計(jì)數(shù)值

在加行鎖之前必須先獲得表級(jí)意向鎖,否則等待 innodb_lock_wait_timeout 超時(shí)后根據(jù)innodb_rollback_on_timeout 決定是否回滾事務(wù)。


InnoDB 自增鎖

在 MySQL InnoDB 存儲(chǔ)引擎中,我們?cè)谠O(shè)計(jì)表結(jié)構(gòu)的時(shí)候,通常會(huì)建議添加一列作為自增主鍵。

這里就會(huì)涉及一個(gè)特殊的鎖:自增鎖(即:AUTO-INC Locks),它屬于表鎖的一種,在 INSERT 結(jié)束后立即釋放。

我們可以執(zhí)行 show engine innodb status\G 來(lái)查看自增鎖的狀態(tài)信息。

在自增鎖的使用過(guò)程中,有一個(gè)核心參數(shù),需要關(guān)注,即 innodb_autoinc_lock_mode,它有0、1、2 三個(gè)值。保持默認(rèn)值即可。


InnoDB 鎖關(guān)系矩陣

+ 表示兼容,- 表示不兼容


InnoDB死鎖問(wèn)題排查思路

在 MySQL 中死鎖不會(huì)發(fā)生在 MyISAM 存儲(chǔ)引擎中,但會(huì)發(fā)生在 InnoDB 存儲(chǔ)引擎中,因?yàn)?InnoDB 是逐行加鎖的,極容易產(chǎn)生死鎖。那么死鎖產(chǎn)生的四個(gè)條件是什么呢?

  • 互斥條件:一個(gè)資源每次只能被一個(gè)進(jìn)程使用;

  • 請(qǐng)求與保持條件:一個(gè)進(jìn)程因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放;

  • 不剝奪條件:進(jìn)程已獲得的資源,在沒(méi)使用完之前,不能強(qiáng)行剝奪;

  • 循環(huán)等待條件:多個(gè)進(jìn)程之間形成的一種互相循環(huán)等待資源的關(guān)系。

在發(fā)生死鎖時(shí),InnoDB 存儲(chǔ)引擎會(huì)自動(dòng)檢測(cè),并且會(huì)自動(dòng)回滾代價(jià)較小的事務(wù)來(lái)解決死鎖問(wèn)題。但很多時(shí)候一旦發(fā)生死鎖,InnoDB 存儲(chǔ)引擎的處理的效率是很低下的或者有時(shí)候根本解決不了問(wèn)題,需要人為手動(dòng)去解決。

排查 InnoDB 鎖問(wèn)題通常有 2 種方法。

  • 打開 innodb_lock_monitor 表,注意使用后記得關(guān)閉,否則會(huì)影響性能。
  • 在 MySQL 5.5 版本之后,可以通過(guò)查看 information_schema 庫(kù)下面的 innodb_locks、innodb_lock_waitsinnodb_trx 三個(gè)視圖排查 InnoDB 的鎖問(wèn)題

基于資源爭(zhēng)用導(dǎo)致死鎖的情況

【基于資源爭(zhēng)用導(dǎo)致死鎖的情況】


session1 首先拿到 id=1 的鎖,session2 同期拿到了 id=5 的鎖后,兩者分別想拿到對(duì)方持有的鎖,于是產(chǎn)生死鎖。


Metadata lock(即元數(shù)據(jù)鎖)導(dǎo)致的死鎖的情況

【Metadata lock(即元數(shù)據(jù)鎖)導(dǎo)致的死鎖的情況】

session1 和 session2 都在搶占 id=1 和 id=6 的元數(shù)據(jù)的資源,產(chǎn)生死鎖。

查看 MySQL 數(shù)據(jù)庫(kù)中死鎖的相關(guān)信息,可以執(zhí)行 show engine innodb status\G 來(lái)進(jìn)行查看,重點(diǎn)關(guān)注 “LATEST DETECTED DEADLOCK” 部分。

開發(fā)建議

  • 更新 SQL 的 where 條件時(shí)盡量用索引

  • 加鎖索引準(zhǔn)確,縮小鎖定范圍

  • 減少范圍更新,尤其非主鍵/非唯一索引上的范圍更新

  • 控制事務(wù)大小,減少鎖定數(shù)據(jù)量和鎖定時(shí)間長(zhǎng)度 (innodb_row_lock_time_avg)

  • 加鎖順序一致,盡可能一次性鎖定所有所需的數(shù)據(jù)行

更多案例參考:MySQL - 鎖等待及死鎖初探


InnoDB 加鎖行為驗(yàn)證

下面舉一些例子分析 InnoDB 不同索引的加鎖行為。分析鎖時(shí)需要跟隔離級(jí)別聯(lián)系起來(lái),我們以 RR 為例,主要是從四個(gè)場(chǎng)景分析。

主鍵 + RR


假設(shè)條件是:

  • update t1 set name=‘XX’ where id=10

  • id 為主鍵索引。

加鎖行為:僅在 id=10 的主鍵索引記錄上加 X鎖。


唯一鍵 + RR


假設(shè)條件是:

  • update t1 set name=‘XX’ where id=10

  • id 為唯一索引。

加鎖行為:

  • 先在唯一索引 id 上加 id=10 的 X 鎖。

  • 再在 id=10 的主鍵索引記錄上加 X 鎖,若 id=10 記錄不存在,那么加間隙鎖。


非唯一鍵 + RR

假設(shè)條件是:

  • update t1 set name=‘XX’ where id=10

  • id 為非唯一索引

加鎖行為:

  • 先通過(guò) id=10 在 key(id) 上定位到第一個(gè)滿足的記錄,對(duì)該記錄加 X 鎖,而且要在 (6,c)~(10,b) 之間加上 Gap lock,為了防止幻讀。然后在主鍵索引 name 上加對(duì)應(yīng)記錄的X 鎖;

  • 再通過(guò) id=10 在 key(id) 上定位到第二個(gè)滿足的記錄,對(duì)該記錄加 X 鎖,而且要在(10,b)~(10,d)之間加上 Gap lock,為了防止幻讀。然后在主鍵索引 name 上加對(duì)應(yīng)記錄的X 鎖;

  • 最后直到 id=11 發(fā)現(xiàn)沒(méi)有滿足的記錄了,此時(shí)不需要加 X 鎖,但要再加一個(gè) Gap lock: (10,d)~(11,f)。


無(wú)索引 + RR

假設(shè)條件是:

  • update t1 set name=‘XX’ where id=10。

  • id 列無(wú)索引。

加鎖行為:

表里所有行和間隙均加 X 鎖。


搞定MySQL

總結(jié)

以上是生活随笔為你收集整理的MySQL - 锁机制初探的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。