數(shù)據(jù)庫(kù)之鎖模塊

MyISAM與InnoDB關(guān)于鎖方面的區(qū)別

MyISAM與InnoDB關(guān)于鎖方面的區(qū)別:

網(wǎng)站建設(shè)哪家好,找成都創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序制作、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了石鼓免費(fèi)建站歡迎大家使用!

  • MyISAM默認(rèn)使用的是表級(jí)鎖,不支持行級(jí)鎖
  • InnoDB默認(rèn)用的是行級(jí)鎖,也支持表級(jí)鎖
  • InnoDB支持事務(wù),在事務(wù)中被加鎖的數(shù)據(jù)行需要 等事務(wù)commit之后才會(huì)統(tǒng)一解鎖,否則不會(huì)解鎖。而MyISAM不支持事務(wù),所以不會(huì)有這個(gè)問(wèn)題
  • MyISAM和InnoDB都支持共享鎖和排他鎖,讀鎖共享,寫鎖排他
  • InnoDB在開啟事務(wù)時(shí),若select語(yǔ)句不走索引的情況會(huì)鎖住整張表,也就是說(shuō)InnoDB在SQL沒(méi)有利用到索引的時(shí)候使用的是表級(jí)鎖,而SQL用到索引的時(shí)候則是使用行級(jí)鎖和gap鎖,gap鎖是走普通非唯一索引時(shí)用到的
  • InnoDB除了支持行級(jí)鎖之外,還支持表級(jí)的意向鎖,意向鎖分為共享讀鎖(IS)和排他寫鎖(IX)

注:

實(shí)際上在不走索引的時(shí)候,InnoDB的實(shí)現(xiàn)方式和MyIsam的表鎖方式不同,單條索引記錄上加鎖,record lock鎖住的永遠(yuǎn)是索引,而非記錄本身,即使該表上沒(méi)有任何索引,那么innodb會(huì)在后臺(tái)創(chuàng)建一個(gè)隱藏的聚集主鍵索引,那么鎖住的就是這個(gè)隱藏的聚集主鍵索引。所以說(shuō)當(dāng)一條sql沒(méi)有走任何索引時(shí),那么將會(huì)在每一條聚集索引后面加X(jué)鎖(排他鎖),此時(shí)想改變樹型結(jié)構(gòu)即索引結(jié)構(gòu)的話,是會(huì)被鎖住的,這個(gè)類似于表鎖,但原理上和表鎖是完全不同的

MyISAM適合的場(chǎng)景:

  • 頻繁執(zhí)行全表count語(yǔ)句
  • 對(duì)數(shù)據(jù)進(jìn)行增刪改的頻率不高,而查詢非常頻繁的場(chǎng)景
  • 沒(méi)有事務(wù)場(chǎng)景

InnoDB適合的場(chǎng)景:

  • 數(shù)據(jù)進(jìn)行增刪改查都相當(dāng)頻繁的系統(tǒng)
  • 可靠性要求比較高,需要事務(wù)特性的系統(tǒng)

數(shù)據(jù)庫(kù)鎖的分類:

  • 按鎖的粒度劃分,可分為表級(jí)鎖、行級(jí)鎖、頁(yè)級(jí)鎖
  • 按鎖級(jí)別劃分,可分為共享鎖、排他鎖
  • 按加鎖方式劃分,可分為自動(dòng)鎖、顯式鎖
  • 按操作劃分,可分為DML鎖、DDL鎖
  • 按使用方式劃分,可分為樂(lè)觀鎖、悲觀鎖;悲觀鎖通常需要利用數(shù)據(jù)庫(kù)提供的鎖機(jī)制來(lái)實(shí)現(xiàn);而樂(lè)觀鎖通常用版本號(hào)或時(shí)間戳來(lái)實(shí)現(xiàn)

總結(jié):

MyISAM默認(rèn)使用的是表級(jí)鎖,不支持行級(jí)鎖。InnoDB默認(rèn)用的是行級(jí)鎖,也支持表級(jí)鎖。無(wú)論是表級(jí)鎖還是行級(jí)鎖,均分為共享鎖和排他鎖,它們的關(guān)系如下表所示(X:排他鎖,S:共享鎖):
數(shù)據(jù)庫(kù)之鎖模塊


事務(wù)隔離級(jí)別以及各級(jí)別下的并發(fā)訪問(wèn)問(wèn)題以及事務(wù)隔離機(jī)制

事務(wù)并發(fā)訪問(wèn)引起的問(wèn)題以及如何避免:

1.更新丟失:

即一個(gè)事務(wù)的更新覆蓋了另一個(gè)事務(wù)的更新;由于現(xiàn)在主流數(shù)據(jù)庫(kù)都會(huì)自動(dòng)加鎖來(lái)避免更新丟失的情況,所以在數(shù)據(jù)庫(kù)層面通常不會(huì)發(fā)生這個(gè)問(wèn)題。例如MySQL所有事務(wù)隔離級(jí)別在數(shù)據(jù)庫(kù)層面上均可避免更新丟失

下圖模擬了更新丟失的過(guò)程:
數(shù)據(jù)庫(kù)之鎖模塊

2.臟讀(Dirty read):

即一個(gè)事務(wù)讀到另一個(gè)事務(wù)的未提交數(shù)據(jù);該問(wèn)題在READ-COMMITTED(讀已提交)以上的事務(wù)隔離級(jí)別可避免

3.不可重復(fù)讀(Non-repeatable read):

即事務(wù)A多次讀取同一數(shù)據(jù),但事務(wù)B在事務(wù)A多次讀取的過(guò)程中對(duì)該數(shù)據(jù)做了更新操作并提交,導(dǎo)致事務(wù)A多次讀取同一數(shù)據(jù)時(shí)結(jié)果不一致;該問(wèn)題在REPEATABLE-READ(可重復(fù)讀)以上的事務(wù)隔離級(jí)別可避免,這也是MySQL的默認(rèn)隔離級(jí)別

4.幻讀(Phantom read):

事務(wù)A讀取以搜索條件相匹配的若干行數(shù)據(jù),而事務(wù)B則對(duì)事務(wù)A查詢匹配的數(shù)據(jù)進(jìn)行了插入或刪除操作,導(dǎo)致事務(wù)A多次讀取的結(jié)果集行數(shù)不一致;該問(wèn)題在SERIALIZABLE(串行化)以上的事務(wù)隔離級(jí)別可避免,需要注意的是:在MySQL數(shù)據(jù)庫(kù)中,REPEATABLE-READ事務(wù)隔離級(jí)別下也可以避免幻讀

總結(jié):
數(shù)據(jù)庫(kù)之鎖模塊


當(dāng)前讀和快照讀

表象:快照讀(非阻塞讀)-- 偽MVCC(多版本并發(fā)控制)
內(nèi)在:next-key鎖(行級(jí)鎖+gap鎖)

首先我們需要知道兩個(gè)概念:當(dāng)前讀和快照讀;當(dāng)前讀其實(shí)就是加了鎖的增刪改查語(yǔ)句,例:

  • select ... lock in share mode;select ... for update
  • update,delete,insert(自動(dòng)加鎖)

之所以叫當(dāng)前讀,是因?yàn)樽x取的是當(dāng)前記錄的最新版本,而RR事務(wù)隔離級(jí)別下在讀取數(shù)據(jù)之后還需要保證其他事務(wù)不能修改當(dāng)前記錄,那么就會(huì)對(duì)讀取的記錄加next-key鎖,所以RR事務(wù)隔離級(jí)別下的當(dāng)前讀可以避免發(fā)生幻讀現(xiàn)象:
數(shù)據(jù)庫(kù)之鎖模塊

快照讀則是不加鎖的非阻塞讀,例如不加鎖的普通select操作。但需要注意的是在串行化的事務(wù)隔離級(jí)別下,任何的增刪改查操作都會(huì)被加鎖。

在mysql中,讀已提交隔離級(jí)別下,快照讀和當(dāng)前讀都是讀到同樣的數(shù)據(jù)。而在可重復(fù)讀隔離級(jí)別下,快照讀讀到的是開啟事務(wù)時(shí)第一條select語(yǔ)句讀到的快照版本數(shù)據(jù),當(dāng)前讀則是會(huì)讀到當(dāng)前數(shù)據(jù)庫(kù)中最新的數(shù)據(jù)。

RC、RR級(jí)別下的InnoDB的快照讀(非阻塞讀)是如何實(shí)現(xiàn)的:

  • 一是依靠數(shù)據(jù)行里的隱藏字段:DB_TRX_ID、DB_ROLL_PTR、DB_ROW_ID字段
    • DB_TRX_ID:最后修改本行數(shù)據(jù)的事務(wù)id
    • DB_ROLL_PTR:回滾指針,指向undo日志的歷史版本數(shù)據(jù)
    • DB_ROW_ID:行號(hào),即密集索引維護(hù)的自增id
  • 二是undo日志,當(dāng)我們對(duì)數(shù)據(jù)進(jìn)行變更操作時(shí)就會(huì)產(chǎn)生undo日志,undo日志中存儲(chǔ)的是歷史數(shù)據(jù),當(dāng)一個(gè)舊事務(wù)需要讀取數(shù)據(jù)時(shí),會(huì)順著undo鏈找到滿足其可見性的數(shù)據(jù);undo日志還分為insert undo日志和update undo日志
    • insert undo日志:記錄insert操作產(chǎn)生的undo日志,該日志記錄只在事務(wù)回滾時(shí)需要,而在事務(wù)提交后會(huì)立即丟棄
    • update undo日志:記錄update或delete操作產(chǎn)生的undo日志,該日志記錄不僅在事務(wù)回滾時(shí)需要,快照讀也需要,所以不會(huì)馬上被刪除,只有當(dāng)數(shù)據(jù)庫(kù)所使用的快照中不涉及該日志記錄才會(huì)被刪除
  • 三是read view,它主要用來(lái)做可見性判斷的,即當(dāng)我們?nèi)?zhí)行快照讀時(shí),會(huì)針對(duì)我們查詢的數(shù)據(jù)創(chuàng)建一個(gè)read view,以此來(lái)決定該事務(wù)能看到的是哪個(gè)版本的數(shù)據(jù)。read view的創(chuàng)建時(shí)機(jī)是開啟事務(wù)后執(zhí)行的第一條select語(yǔ)句
    • read view遵循一個(gè)可見性算法,該算法會(huì)先取出將要變更數(shù)據(jù)行的DB_TRX_ID,與系統(tǒng)其他活躍的事務(wù)id做對(duì)比,如果大于等于這些活躍的事務(wù)id就會(huì)通過(guò)DB_ROLL_PTR去undo日志里取出DB_TRX_ID小于當(dāng)前活躍事務(wù)id的歷史數(shù)據(jù)

事務(wù)對(duì)行的更新過(guò)程:
數(shù)據(jù)庫(kù)之鎖模塊
數(shù)據(jù)庫(kù)之鎖模塊


RR事務(wù)隔離級(jí)別下是如何避免幻讀的

在之前的小節(jié)中,我們了解到在MySQL的RR事務(wù)隔離級(jí)別下,是可以避免幻讀的。但并不意味著快照讀是避免發(fā)生幻讀現(xiàn)象的根本,因?yàn)榭煺兆x只是讀的發(fā)生變化前的歷史數(shù)據(jù)。實(shí)際在RR及SERIALIZABLE事務(wù)隔離級(jí)別下真正防止幻讀發(fā)生的原因是事務(wù)對(duì)數(shù)據(jù)加上了next-key鎖,而next-key鎖由行鎖和gap鎖兩部分組成。行鎖就不多說(shuō)了,gap鎖才是重點(diǎn),所謂gap就是索引樹中插入新記錄的間隙,而gap鎖是用于鎖定一個(gè)間隙范圍但不包括記錄本身,gap鎖的目的是為了防止同一事務(wù)的兩次當(dāng)前讀而導(dǎo)致出現(xiàn)幻讀的情況。

gap鎖只在RR和SERIALIZABLE事務(wù)隔離級(jí)別中存在,其他的隔離級(jí)別是沒(méi)有的,所以RC和RU是無(wú)法避免幻讀的。這里我們主要討論RR事務(wù)隔離級(jí)別下gap鎖出現(xiàn)的場(chǎng)景:

  • 增刪改查及當(dāng)前讀若用到主鍵索引或唯一索引會(huì)對(duì)其加gap鎖嗎?
    • 答:視情況而定,如果where條件全部命中,則不會(huì)用gap鎖,只會(huì)加行鎖;而where條件部分命中或者全不命中,則會(huì)加gap鎖;所以gap鎖會(huì)用在非唯一索引或者不走索引的當(dāng)前讀中

where條件全部命中,只會(huì)加行鎖:
數(shù)據(jù)庫(kù)之鎖模塊

走非唯一索引時(shí)會(huì)對(duì)該索引間隙加gap鎖:
數(shù)據(jù)庫(kù)之鎖模塊

不走索引則會(huì)對(duì)表里所有的間隙加gap鎖,其效果就類似于表級(jí)鎖了,但是其代價(jià)比表級(jí)鎖更大:
數(shù)據(jù)庫(kù)之鎖模塊

總結(jié):

無(wú)論是當(dāng)前讀還是快照讀,在innodb的RR的事務(wù)隔離級(jí)別下都可以避免幻讀。在快照讀的情況下,innodb通過(guò)mvcc來(lái)避免幻讀;在當(dāng)前讀的情況下,innodb通過(guò)next-key鎖來(lái)避免幻讀。

網(wǎng)站標(biāo)題:數(shù)據(jù)庫(kù)之鎖模塊
本文鏈接:http://bm7419.com/article14/igehge.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供響應(yīng)式網(wǎng)站、品牌網(wǎng)站制作、網(wǎng)站設(shè)計(jì)、網(wǎng)站收錄App設(shè)計(jì)、關(guān)鍵詞優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)