mysql事務與鎖機制

什么是事務?

官方點說,事務就是數據庫管理系統執行過程中的一個邏輯單位,由一個有限的數據庫操作作序列構成。

通俗點說,事務就是一組操作要么同時成功要么同時失敗。

事務的四大特性(ACID):

1.原子性(atomicity):一個事務必須視為一個不可分割的最小工作單元,整個事務中的所有操作要么全部提交成功,要么全部失敗回滾,對于一個事務來說,不可能只執行其中的一部分操作,這就是事務的原子性。

2.一致性(consistency):數據庫總數從一個一致性的狀態轉換到另一個一致性的狀態。

3.隔離性(isolation):一個事務所做的修改在最終提交以前,對其他事務是不可見的。

4.持久性(durability):一旦事務提交,則其所做的修改就會永久保存到數據庫中。此時即使系統崩潰,修改的數據也不會丟失。

事務并發帶來的問題:

1.臟讀:臟讀是指一個事務在處理過程中讀取了另一個事務未提交的數據。

2.不可重復讀:指的是在一個事務處理中讀取到其他事務修改或刪除并提交的數據,導致多次讀取結果不一致。

3.幻讀:指的是在一個事務處理中讀取到其他事務插入并提交的數據,導致多次讀取結果不一致。

事務并發帶來的三大問題其實都是數據庫讀一致性問題,必須由數據庫提供一定的事務隔離機制來解決。

mysql事務的隔離級別:

事務隔離級別臟讀不可重復讀幻讀

讀未提交(read-uncommitted)可能可能可能

不可重復讀(read-committed)不可能可能可能

可重復讀(repeatable-read)不可能不可能在InnoDB中不可能

串行化(serializable)不可能不可能不可能

為什么InnoDB中在rr級別的時候就解決了幻讀這個問題?

MVCC與LBCC

如果要解決讀一致性問題,保證一個事務前后讀取數據結果的一致性,實現事務隔離應該怎么做?

簡單思考下解決方案:

LBCC(全稱Lock Based Concyrrency Control):在讀取數據前對其加鎖,阻止其他事務對數據進行修改。

MVCC(全稱Multi Version Concurrency Control):生成一個數據請求時間點的一致性數據快照(snapshot),并用這個快照來提供一定級別(語句級或者事務級)的一致性讀取。

InnoDB中怎么實現的MVCC

其實InnoDB中,自動為每一行數據添加了三個隱藏字段:

DB_ROW_ID(6字節):行標識,前邊的文章中提到過這個字段。

DB_TRX_ID(6字節):創建版本號,插入或更新行的最后一個事務的id,自動遞增。

DB_ROLL_PIR(7字節):刪除版本號,用于回滾。

主要記住,在InnoDB中,一個事務開始時,會生成一個當前時間點的數據快照(可以理解為一個副本),只要事務不結束,他就只能在這個數據快照里查找數據,也就是只能查找到創建版本號小于當前事務id的數據和刪除版本號大于當前事務id的數據(或者是在創建版本號小于當前事務id的前提下,沒有刪除版本號的數據)

在InnoDB中MVCC和鎖是相互配合使用的,下邊就看看鎖的東西。

表鎖與行鎖的區別:

鎖定粒度:表鎖 > 行鎖

加鎖效率:表鎖 > 行鎖

沖突概率:表鎖 > 行鎖

并發性能:表鎖 < 行鎖

注意:MYISAM引擎只支持表鎖,InnoDB既支持表鎖也支持行鎖

行鎖

共享鎖(Shared Locks):

又稱為讀鎖,簡稱s鎖,顧名思義共享鎖就是多個事務對于同一數據可以共享一把鎖,都能訪問到數據,但是只能讀不能寫,不然容易造成死鎖。

加鎖方式:在select語句后加LOCK IN SHARE MODE;

釋鎖方式:commit / rollback

排他鎖(Exclusive Locks):

又稱為寫鎖,簡稱x鎖,排他鎖不能和其他鎖共存,如一個事務獲取了一個數據行的排他鎖,其他事務就不能獲取該行的鎖(包括共享鎖和排他鎖),只有獲取到該行的排他鎖的事務是可以對數據進行讀取和修改。

加鎖方式:

1.手動加鎖:在語句后加FOR UPDATE;(select時需手動)

2.自動加鎖:在insert / update / delete 語句時或自動加排他鎖

釋鎖方式:commit / rollback

注意:innoDB中獲取鎖超時間默認為50秒,查看語句為show variables like 'innodb_lock_wait_timeout';。

表鎖

意向共享鎖(Intention Shared Lock):

簡稱IS鎖,表示事務準備給數據行進行加入共享鎖,也就是說一個數據行加共享鎖之前必須先獲得該表的IS鎖。

意向排他鎖(Intention Exclusive Lock):

簡稱IX鎖,表示事務準備給數據行加入排他鎖,說明事務在一個數據行加排他鎖前必須要獲得該表的IX鎖。

注意:意向鎖是由數據引擎自己維護的,用戶是無法手動操作意向鎖的。

問:為什么需要表級別的意向鎖?

答:假如要給一張表加表鎖,那么這個加表鎖的前提是沒有其他任何事務已經鎖住了這張表的任意一行數據。那么怎么來確定這個前提呢?

必然要有一個全表掃描才能確定每一行數據都沒有被加鎖。如果這張表數據比較大呢?有千萬數據,那這個全表掃描的過程就要消耗很多時間才能確定能不能加表鎖,并且如果在掃描的過程中萬一有其他事務來加鎖怎么辦,所以說,全表掃描加表鎖這種方式既慢并且消耗性能,帶來嚴重的并發問題。為了解決這一問題,才有了意向鎖。加表鎖的時候只要看一下這個表上有沒有意向鎖就ok了,因為你加行鎖的時候都會先獲取到表的意向鎖才行。意向鎖就是為了提高加表鎖的效率。

問:鎖的作用?

答:和Java中的鎖一樣,都是為了解決資源競爭的問題,Java中的資源是對象。而數據庫中的資源就是表和行數據,鎖就是為了解決對于事務并發訪問的問題。

問:鎖到底鎖住了什么?是一行數據?還是一個字段?

InnoDB行鎖原理

針對上述問題,其實有三種情況:

1.沒有索引的表上加行鎖,會鎖住整張表,出現鎖表的情況。

2.有主鍵索引的表上加行鎖,會鎖住索引。

3.用唯一索引(輔助索引)的字段加行鎖,會鎖住輔助索引和主鍵索引。

在InnoDB中,行鎖就是鎖住索引記錄來實現的,加鎖的時候在mysql自帶的information_schema庫中的INN0DB_LOCKS表中可以看到:

lock_type:鎖類型;lock_table:加鎖的表;lock_index:鎖住的索引

問:沒有索引的表上加行鎖為什么會鎖表?

注意:在之前的文章中說過,InnoDB中一張表是不可能沒有索引的,如果用戶沒定義,默認就會用隱藏的字段ROW_ID作為聚集索引。那么加行鎖的時候,條件沒有命中索引(因為用的是隱藏字段作為索引,那么肯定不能命中啊),就會走全表掃描,不得不把所有的聚集索引全都鎖住,所以會出現鎖表的情況。

問:為什么用唯一索引加行鎖時,會鎖住主鍵索引?

這就又涉及到前邊的知識——回表,因為InnoDB中,輔助索引的葉子節點上存放的是主鍵索引,索引用輔助索引加行鎖時會先鎖住輔助索引,然后鎖住主鍵索引。本質上其實還是鎖住了主鍵索引。那么鎖到底鎖住了什么?相信大家心里已經有答案了。

InnoDB行鎖算法

主要有三種算法:

1.記錄鎖(Record Lock)

鎖定記錄,在唯一性索引(唯一/主鍵)等值查詢時,精準匹配到一個索引記錄的時候會使用記錄鎖。

(如下圖)比如用where id = 4這個條件時,就會精準匹配到一個索引記錄。

2.間隙鎖(Gap Lock)

鎖定區間,鎖定是的是數據庫不存在的區間范圍,Gap Lock相互之間不會沖突。

比如,用where id = 6這個條件時,發現沒有這個數據記錄,就會鎖住(4,7)這個范圍(注意左開右開不包括記錄)。

3.臨建鎖(Next-key Lock)

鎖定記錄和區間,條件范圍查找時,會鎖住記錄和區間。Next-key Lock = Record Lock + Gap Lock;

比如,用where id > 5 and id <9時,就會鎖住(4,7]和(7,10]這個范圍的區間和記錄,也就是(4,10]這個范圍的記錄和區間(注意是左開右閉,不包括左邊的記錄,包括右邊的記錄)

事務隔離級別的選擇

首先Read Uncommited不加鎖和Serializable串行化這兩種級別基本是不會被使用的。

Read Commited 對于普通的select語句使用mvcc,對于加鎖的select和更新語句使用Record Lock記錄鎖。

Repeatable Read 對于普通的select語句使用mvcc,對于加鎖的select和更新語句會使用Next-key Lock 、 Record Lock 、 Gap Lock。

1.RR的間隙鎖會導致鎖的范圍擴大

2.條件列未使用到索引時,RR鎖表,RC鎖行

3.RC的“半一致性”讀(semi-consistent)可以增加update操作的并發性。

從上述三個問題中,看似RC的級別更有優勢,其實在實際中,合理的加鎖,在有索引的列加鎖并不會出現上邊的情況,通常使用默認的事務隔離級別RR就ok了。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,115評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,234評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,621評論 1 326
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,822評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,380評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,128評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,319評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,548評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,048評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,285評論 2 376

推薦閱讀更多精彩內容