a亚洲精品_精品国产91乱码一区二区三区_亚洲精品在线免费观看视频_欧美日韩亚洲国产综合_久久久久久久久久久成人_在线区

首頁 > 數(shù)據(jù)庫(kù) > 文庫(kù) > 正文

InnoDB 事務(wù)加鎖解析

2024-09-07 22:12:56
字體:
供稿:網(wǎng)友
  一般大家對(duì)數(shù)據(jù)庫(kù)事務(wù)的了解可能停留在事務(wù)的ACID特性以及事務(wù)4種不同的隔離級(jí)別層面上,而對(duì)于事務(wù) 4 種不同隔離級(jí)別如何實(shí)現(xiàn)了解相對(duì)較少。
 
  本文以 MySQL 數(shù)據(jù)庫(kù) InnoDB 引擎為例,為大家分析 InnoDB數(shù)據(jù)庫(kù)引擎對(duì)默認(rèn)的隔離級(jí)別可重復(fù)讀(RR)的具體實(shí)現(xiàn)。
 
  整文知識(shí)點(diǎn)介紹:事務(wù)4種隔離級(jí)別、不同隔離級(jí)別解決的問題、MVCC、鎖的類型、加鎖案例分析;閱讀完整文相信大家對(duì)事務(wù)隔離級(jí)別的具體實(shí)現(xiàn)有了一定的認(rèn)識(shí)。
 
  一、事務(wù)的隔離級(jí)別
  1、4 種隔離級(jí)別
  (1)未提交讀(Read uncommitted):一個(gè)事務(wù)讀取到其他事務(wù)未提交的數(shù)據(jù),是級(jí)別最低的隔離機(jī)制;
 
  (2)提交讀(Read committed):一個(gè)事務(wù)讀取到其他事務(wù)提交后的數(shù)據(jù);
 
  (3)可重復(fù)讀(Repeatable read):一個(gè)事務(wù)對(duì)同一份數(shù)據(jù)讀取到的相同,不在乎其他事務(wù)對(duì)數(shù)據(jù)的修改;
 
  (4)序列化(Serializable) :事務(wù)串行化執(zhí)行,隔離級(jí)別最高,犧牲了系統(tǒng)的并發(fā)性。
 
  2、不同隔離級(jí)別解決的問題
  若不考慮事務(wù)的隔離級(jí)別,則事務(wù)的并發(fā)會(huì)造成以下問題:
 
  (1)臟讀:事務(wù)A讀取了事務(wù)B更新的數(shù)據(jù),然后B回滾操作,那么A讀取到的數(shù)據(jù)是臟數(shù)據(jù)。
 
  (2)不可重復(fù)讀:事務(wù) A 多次讀取同一數(shù)據(jù),事務(wù) B 在事務(wù)A多次讀取的過程中,對(duì)數(shù)據(jù)作了更新并提交,導(dǎo)致事務(wù)A多次讀取同一數(shù)據(jù)時(shí),結(jié)果 不一致。
 
  (3)幻讀:同一事務(wù)中對(duì)同一范圍的數(shù)據(jù)進(jìn)行讀取,結(jié)果卻多出了數(shù)據(jù)或者少了數(shù)據(jù),這就叫幻讀。(如同一事務(wù)對(duì)id<10的范圍進(jìn)行2次查詢,第一次出現(xiàn)id=8、9的兩條數(shù)據(jù),第二次出現(xiàn)id=7、8、9的3條數(shù)據(jù))。
 
  不可重復(fù)讀的和幻讀很容易混淆,不可重復(fù)讀側(cè)重于修改,幻讀側(cè)重于新增或刪除。解決不可重復(fù)讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表。

  二、MVCC
  上文提到 InnoDB 默認(rèn)的隔離級(jí)別是可重復(fù)讀(RR),InnoDB是通過MVCC(多版本并發(fā)控制)來實(shí)現(xiàn)可重復(fù)讀的,下面為大家介紹MVCC。
 
  1、概念
  在InnoDB中,給每行增加兩個(gè)隱藏字段來實(shí)現(xiàn)MVCC,一個(gè)用來記錄數(shù)據(jù)行的創(chuàng)建時(shí)間,另一個(gè)用來記錄行的過期時(shí)間(刪除時(shí)間)。在實(shí)際操作中,存儲(chǔ)的并不是時(shí)間,而是事務(wù)的版本號(hào),每開啟一個(gè)新事務(wù),事務(wù)的版本號(hào)就會(huì)遞增。
 
  于是乎,默認(rèn)的隔離級(jí)別(REPEATABLE READ)下,增刪查改變成了這樣:
 
  (1)SELECT
 
  讀取創(chuàng)建版本小于或等于當(dāng)前事務(wù)版本號(hào),并且刪除版本為空或大于當(dāng)前事務(wù)版本號(hào)的記錄。這樣可以保證在讀取之前記錄是存在的。
  (2)INSERT

  (3)UPDATE
 
  新插入一行,并以當(dāng)前事務(wù)的版本號(hào)作為新行的創(chuàng)建版本號(hào),同時(shí)將原記錄行的刪除版本號(hào)設(shè)置為當(dāng)前事務(wù)版本號(hào)。
  (4)DELETE
 
  2、快照讀和當(dāng)前讀
  (1)快照讀:讀取的是快照版本,也就是歷史版本;
 
  (2)當(dāng)前讀:讀取的是最新版本。
 
  普通的SELECT就是快照讀,而UPDATE、DELETE、INSERT、SELECT ...  LOCK IN SHARE MODE、SELECT ... FOR UPDATE是當(dāng)前讀。
 
  (3)結(jié)論:如果隔離級(jí)別是REPEATABLE READ,那么在同一個(gè)事務(wù)中的所有普通select讀讀到的都是事務(wù)第一個(gè)讀到的快照,如此實(shí)現(xiàn)了可重復(fù)讀;而對(duì)于當(dāng)前讀(UPDATE、DELETE、INSERT、SELECT ... LOCK IN SHARE MODE、SELECT ... FOR UPDATE),InnoDB 通過加鎖來實(shí)現(xiàn)可重復(fù)讀,且InnoDB 加鎖同時(shí)解決了幻讀問題。
 
  三、鎖的類型
  InnoDB 引入以下三種鎖類型:
 
  Record Locks(記錄鎖):在索引記錄上加鎖,即行鎖,鎖住當(dāng)前行。
  Gap Locks(間隙鎖):在索引記錄之間加鎖,或者在第一個(gè)索引記錄之前加鎖,或者在最后一個(gè)索引記錄之后加鎖。
  Next-Key Locks:在索引記錄上加鎖,并且在索引記錄之前的間隙加鎖。它相當(dāng)于是Record Locks與Gap Locks的一個(gè)結(jié)合。
  假設(shè)一個(gè)索引包含以下幾個(gè)值:10,11,13,20。那么這個(gè)索引的next-key鎖將會(huì)覆蓋以下區(qū)間:(-oo, 10]、(10, 11]、(11, 13]、(13, 20]、(20, +oo)。
 
  MySQL InnoDB 通過間隙鎖解決了幻讀問題。以下通過實(shí)際的案例分析來介紹InnoDB 是如果解決幻讀問題的。
 
  四、案例分析
  在對(duì)SQL進(jìn)行加鎖分析前,需要明確表的結(jié)構(gòu)和索引類型。在不知道索引的情況下直接給出一條SQL來分析如果加鎖是沒有任何意義的。
 
  以下以用戶表(t_user)為例(id為主鍵,name為唯一索引,age為一般索引,address無索引)分析不同索引條件的加鎖表現(xiàn)。
 
  1、主鍵索引
  例:delete from t_user where id=120;
 
  此種情況下,其他事務(wù)除了不能刪除、更新此條記錄外,其他插入其他行、更新其他行都行。
 
  2、唯一索引
  例:delete from t_user where name='n20';
  條件為唯一索引,鎖住索引記錄,同時(shí)鎖住聚簇索引中的對(duì)應(yīng)行記錄:
 
  3、一般索引
  例:delete from t_user where age=20;
  與主鍵和唯一索引不同的是,一般索引的記錄是允許重復(fù)的;換句話說,如果我們單純地給索引加記錄鎖時(shí),其他事務(wù)依然可以插入,也就有可能出現(xiàn)幻讀問題了。
 
  所以除了給對(duì)應(yīng)索引記錄加上記錄鎖之外,還要給Gap加上鎖。
 
  從上面知識(shí)點(diǎn)我們可以預(yù)估這個(gè)操作一共需要的鎖:
 
  age索引記錄鎖(Record Lock) : 20_120, 20_130(以下均用age_id這種形式表示索引值)
  age索引間隙鎖(Gap X-Lock): (10, 20)、(20, 20)、(20, 40)
  聚簇索引上的記錄鎖(Record X-Lock): id=120/130對(duì)應(yīng)的行記錄
  SQL驗(yàn)證:
 
  根據(jù)實(shí)際情況,3-6均符合我們預(yù)期,然而7和8則超出了我們預(yù)期的鎖范圍。為什么會(huì)超出我們預(yù)期呢?此次我們進(jìn)行分析一下:
 
  從7、8插入語句來看,由于id為自增主鍵,會(huì)自動(dòng)遞增,語句7插入值預(yù)計(jì)為:10_141;
 
  語句8插入值預(yù)計(jì)為:40_141,為什么只有后者能插入呢?
  其實(shí)我們可以將B+樹中的間隙理解得更加精準(zhǔn)一點(diǎn):
 
  age=20的三個(gè)間隙應(yīng)該為:(10_110, 20_120)、(20_120, 20_130)、(20_130, 40_140);
 
  可以看出語句7插入值10_141 無法插入,因?yàn)殚g隙被鎖住了;而語句8插入 40_141值因?yàn)樵陂g隙之外了,無鎖沖突,允許插入。
 
  所以最終的加鎖情況應(yīng)該這樣表示:
 
  age索引記錄鎖(Record Lock) :20_120, 20_130
  age索引間隙鎖(Gap X-Lock):(10_110, 20_120)、(20_120, 20_130)、(20_130, 40_140)
  聚簇索引上的記錄鎖(Record X-Lock):id=120/130對(duì)應(yīng)的行記錄
  4、無索引
  delete from t_user where address='a20',因?yàn)闊o法精準(zhǔn)定位,InnoDB選擇將聚簇索引中的所有行以及間隙都鎖起來,功能上已經(jīng)等于鎖表了:
 
  5、結(jié)論
  InnoDB 在RC(READ COMMITTED)隔離級(jí)別中,只會(huì)在對(duì)應(yīng)的索引/行記錄上加Record Lock,而不會(huì)加Gap鎖,原因也很簡(jiǎn)單,因?yàn)樵摳綦x級(jí)別是允許存在幻讀問題的。
 
  在RR級(jí)別下的加鎖方式稱之為Next-Key Locks,其實(shí)就是上述Record Locks和Gap Locks的結(jié)合。比如Gap Lock為(10,20) ,record lock為20,結(jié)合的Next-Key lock 為:(10, 20]。
 
  分析Next-Key Locks其實(shí)就是要分析Record Locks和Gap Locks。MySQL InnoDB的可重復(fù)讀并不保證避免幻讀,需要應(yīng)用使用加鎖讀來保證。而這個(gè)加鎖讀使用到的機(jī)制就是next-key locks。
 
  如果使用普通的讀,會(huì)得到一致性的結(jié)果,如果使用了加鎖的讀,就會(huì)讀到“最新的”“提交”讀的結(jié)果。本身,可重復(fù)讀和提交讀是矛盾的。在同一個(gè)事務(wù)里,如果保證了可重復(fù)讀,
 
  就會(huì)看不到其他事務(wù)的提交,違背了提交讀;如果保證了提交讀,就會(huì)導(dǎo)致前后兩次讀到的結(jié)果不一致,違背了可重復(fù)讀。可以這么講,InnoDB提供了這樣的機(jī)制,在默認(rèn)的可重復(fù)讀的隔離級(jí)別里,可以使用加鎖讀去查詢最新的數(shù)據(jù)。

(編輯:武林網(wǎng))

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 蜜桃久久久久久 | 色婷婷综合久久久中文字幕 | 1000部羞羞视频在线看视频 | 亚洲视频第一页 | yy6080久久伦理一区二区 | 毛片av基地 | 日韩精品一区二区三区老鸭窝 | 欧美狠狠操| 日韩精品小视频 | av网址大全在线观看 | 国内精品国产三级国产在线专 | 日韩在线播放网址 | 亚洲成人第一页 | 欧美日韩国产一区二区三区 | 人人插人人爽 | 无码日韩精品一区二区免费 | 欧美精品一区二区三区在线 | avmans最新导航地址 | 欧美一级免费看 | 亚洲精品久久久久久久久久久久久 | 欧美精品一区二区三区在线四季 | 五月婷婷在线播放 | 精品久久久久久一区二区 | 亚洲精品亚洲人成人网 | 免费观看国产黄色 | 成视频年人免费看黄网站 | 日韩精品网站在线观看 | 日韩无 | 亚洲精品日韩激情欧美 | 有码一区 | 九九精品视频在线观看 | 欧美成人精品一区二区三区 | 亚洲第一男人天堂 | 老牛嫩草一区二区三区眼镜 | 久久99精品国产91久久来源 | 国产欧美一区二区三区国产幕精品 | 国产一区二区三区在线免费 | 久草久草 | 青青久在线视频免费观看 | av第一页| 久久精品在线 |