mysql - 事務

Sql請求的過程

image.png

優(yōu)化器:你以為你的sql就是你的sql?

事務

原子性

一致性

持久性

隔離性

隔離性

WHY

臟讀

原因
因為其他事務回滾導致的

讀到了并一定最終存在的數(shù)據(jù)焰雕,這就是臟讀无牵。如:
1.事務A改變了訂單表的某條數(shù)據(jù)的訂單狀態(tài)為“已發(fā)貨”
2.事務B獲取該條數(shù)據(jù)的訂單狀態(tài)為“已發(fā)貨”
3.事務A發(fā)生錯誤了,進行了回滾撵幽,訂單狀態(tài)由“已發(fā)貨”改為了“待發(fā)貨”
4.事務B拿著錯誤的“已發(fā)貨”狀態(tài)遗菠,去進行后續(xù)操作

可重復讀

是在一個事務內列肢,最開始讀到的數(shù)據(jù)和事務結束前的任意時刻讀到的同一批數(shù)據(jù)都是一致的。通常針對數(shù)據(jù)更新(UPDATE)操作官册。
如:

  1. 事務A先將訂單狀態(tài)由“待發(fā)貨” 改為 “已發(fā)貨”生兆,但事務A暫未提交
  2. 事務A內再次 讀到訂單狀態(tài),為“待發(fā)貨”

不可重復讀

原因
因為其他事務的提交導致的

對比可重復讀膝宁,不可重復讀指的是在同一事務內鸦难,不同的時刻讀到的同一批數(shù)據(jù)可能是不一樣的,可能會受到其他事務的影響员淫,比如其他事務改了這批數(shù)據(jù)并提交了合蔽。通常針對數(shù)據(jù)更新(UPDATE)操作。
如:

  1. 事務A先將訂單狀態(tài)由“待發(fā)貨” 改為 “已發(fā)貨”介返,但事務A暫未提交
  2. 事務A內再次 讀到訂單狀態(tài)拴事,為“已發(fā)貨”

幻讀

原因
因為其他事務在本事務之后開始,又在本事務結束之前結束

1.事務A將訂單狀態(tài)由“待發(fā)貨”改為“已發(fā)貨”
2.事務B將訂單狀態(tài)改為“待發(fā)貨”
3.事務B提交
4.事務A還未提前之前圣蝎,檢查訂單狀態(tài)刃宵,發(fā)現(xiàn)還是“待發(fā)貨”,像是出現(xiàn)了幻覺

隔離級別

隔離級別


image.png

讀未提交(READ UNCOMMIT)

如:
啟動兩個事務徘公,分別為事務A和事務B牲证,在事務A中使用 update 語句,修改 age 的值為10关面,初始是1 坦袍,在執(zhí)行完 update 語句之后缭裆,在事務B中查詢 user 表,會看到 age 的值已經(jīng)是 10 了澈驼,這時候事務A還沒有提交,而此時事務B有可能拿著已經(jīng)修改過的 age=10 去進行其他操作了。在事務B進行操作的過程中挎塌,很有可能事務A由于某些原因徘六,進行了事務回滾操作榴都,那其實事務B得到的就是臟數(shù)據(jù)了,拿著臟數(shù)據(jù)去進行其他的計算嘴高,那結果肯定也是有問題的竿音。

讀未提交,其實就是可以讀到其他事務未提交的數(shù)據(jù)拴驮,但沒有辦法保證你讀到的數(shù)據(jù)最終一定是提交后的數(shù)據(jù)春瞬,如果中間發(fā)生回滾套啤,那就會出現(xiàn)臟數(shù)據(jù)問題,讀未提交沒辦法解決臟數(shù)據(jù)問題萄涯。更別提可重復讀和幻讀了唆鸡,想都不要想。

讀未提交喇闸,它是性能最好,也可以說它是最野蠻的方式唆樊,因為它壓根兒就不加鎖刻蟹,所以根本談不上什么隔離效果,可以理解為沒有隔離

讀提交(READ COMMIT)

讀提交每次執(zhí)行語句的時候都要重新創(chuàng)建一次快照

同樣開啟事務A和事務B兩個事務舆瘪,在事務A中使用 update 語句將 id=1 的記錄行 age 字段改為 10。此時淀衣,在事務B中使用 select 語句進行查詢召调,我們發(fā)現(xiàn)在事務A提交之前蛮浑,事務B中查詢到的記錄 age 一直是1只嚣,直到事務A提交,此時在事務B中 select 查詢册舞,發(fā)現(xiàn) age 的值已經(jīng)是 10 了蕴掏。

這就出現(xiàn)了一個問題调鲸,在同一事務中(本例中的事務B),事務的不同時刻同樣的查詢條件藐石,查詢出來的記錄內容是不一樣的,事務A的提交影響了事務B的查詢結果,這就是不可重復讀角雷,也就是讀提交隔離級別性穿。
每個 select 語句都有自己的一份快照,而不是一個事務一份需曾,所以在不同的時刻,查詢出來的數(shù)據(jù)可能是不一致的商源。

讀提交解決了臟讀的問題谋减,但是無法做到可重復讀,也沒辦法解決幻讀

可重復讀((REAPEAT READ)默認)

僅僅在事務開始是創(chuàng)建一次快照

可重復是對比不可重復而言的庄吼,上面說不可重復讀是指同一事物不同時刻讀到的數(shù)據(jù)值可能不一致严就。而可重復讀是指,事務不會讀到其他事務對已有數(shù)據(jù)的修改渐行,及時其他事務已提交,也就是說殊轴,事務開始時讀到的已有數(shù)據(jù)是什么,在事務提交前的任意時刻樊零,這些數(shù)據(jù)的值都是一樣的孽文。但是,對于其他事務新插入的數(shù)據(jù)是可以讀到的沉衣,這也就引發(fā)了幻讀問題

MySQL 的可重復讀隔離級別其實解決了幻讀問題

串行化(SERIALIZE)

串行化是4種事務隔離級別中隔離效果最好的减牺,解決了臟讀、可重復讀肥隆、幻讀的問題稚失,但是效果最差,它將事務的執(zhí)行變?yōu)轫樞驁?zhí)行句各,與其他三個隔離級別相比,它就相當于單線程矾屯,后一個事務的執(zhí)行必須等待前一個事務結束初厚。

讀的時候加共享鎖,也就是其他事務可以并發(fā)讀骤坐,但是不能寫下愈。寫的時候加排它鎖,其他事務不能并發(fā)寫也不能并發(fā)讀

如何實現(xiàn)事務隔離

實現(xiàn)可重復讀(MVVC多版本并發(fā)控制)

我們在數(shù)據(jù)庫表中看到的一行記錄可能實際上有多個版本拌夏,每個版本的記錄除了有數(shù)據(jù)本身外,還要有一個表示版本的字段障簿,記為 row trx_id,而這個字段就是使其產(chǎn)生的事務的 id皆怕,事務 ID 記為 transaction id西篓,它在事務開始的時候向事務系統(tǒng)申請,按時間先后順序遞增


image.png

在上面介紹讀提交和可重復讀的時候都提到了一個詞虱黄,叫做快照吮成,學名叫做一致性視圖,這也是可重復讀和不可重復讀的關鍵仅醇,可重復讀是在事務開始的時候生成一個當前事務全局性的快照魔种,而讀提交則是每次執(zhí)行語句的時候都重新生成一次快照粉洼。

對于一個快照來說,它能夠讀到那些版本數(shù)據(jù)安拟,要遵循以下規(guī)則

  1. 當前事務內的更新宵喂,可以讀到;
  2. 版本未提交拙泽,不能讀到裸燎;
  3. 版本已提交,但是卻在快照創(chuàng)建后提交的荷荤,不能讀到;
  4. 版本已提交蕴纳,且是在快照創(chuàng)建前提交的,可以讀到***

利用上面的規(guī)則翻翩,再返回去套用到讀提交和可重復讀的那兩張圖上就很清晰了喇潘。還是要強調,兩者主要的區(qū)別就是在快照的創(chuàng)建上絮吵,可重復讀僅在事務開始是創(chuàng)建一次忱屑,而讀提交每次執(zhí)行語句的時候都要重新創(chuàng)建一次

并發(fā)寫問題

存在這的情況,兩個事務伴嗡,對同一條數(shù)據(jù)做修改从铲。最后結果應該是哪個事務的結果呢,肯定要是時間靠后的那個對不對阱扬。并且更新之前要先讀數(shù)據(jù)伸辟,這里所說的讀和上面說到的讀不一樣,更新之前的讀叫做“當前讀”信夫,總是當前版本的數(shù)據(jù)静稻,也就是多版本中最新一次提交的那版。

假設事務A執(zhí)行 update 操作振湾, update 的時候要對所修改的行加行鎖,這個行鎖會在提交之后才釋放佛南。而在事務A提交之前,事務B也想 update 這行數(shù)據(jù)及穗,于是申請行鎖绵载,但是由于已經(jīng)被事務A占有,事務B是申請不到的焚虱,此時懂版,事務B就會一直處于等待狀態(tài),直到事務A提交躯畴,事務B才能繼續(xù)執(zhí)行蓬抄,如果事務A的時間太長,那么事務B很有可能出現(xiàn)超時異常嚷缭。如下圖所示。

加鎖
如果where中的字段有索引路幸,直接加鎖优床;
如果where中沒有索引誓焦,先把所有數(shù)據(jù)都加鎖杂伟,然后再把不滿足條件的數(shù)據(jù)的鎖去掉,性能不好赫粥。

解決幻讀問題

并發(fā)寫問題的解決方式就是行鎖,而解決幻讀用的也是鎖频蛔,叫做間隙鎖,
MySQL 把行鎖和間隙鎖合并在一起瀑粥,解決了并發(fā)寫和幻讀的問題三圆,這個鎖叫做 Next-Key鎖

假設現(xiàn)在表中有兩條記錄,并且 age 字段已經(jīng)添加了索引修噪,兩條記錄 age 的值分別為 10 和 30


image.png

此時路媚,在數(shù)據(jù)庫中會為索引維護一套B+樹,用來快速定位行記錄适荣。B+索引樹是有序的院领,所以會把這張表的索引分割成幾個區(qū)間。


image.png

如圖所示丈氓,分成了3 個區(qū)間万俗,(負無窮,10]饮怯、(10,30]、(30,正無窮]蓖墅,在這3個區(qū)間是可以加間隙鎖的

之后论矾,我用下面的兩個事務演示一下加鎖過程


image.png

在事務A提交之前,事務B的插入操作只能等待饱亿,這就是間隙鎖起得作用。當事務A執(zhí)行update user set name='風箏2號’ where age = 10; 的時候彪笼,由于條件 where age = 10 杰扫,數(shù)據(jù)庫不僅在 age =10 的行上添加了行鎖,而且在這條記錄的兩邊章姓,也就是(負無窮,10]凡伊、(10,30]這兩個區(qū)間加了間隙鎖,從而導致事務B插入操作無法完成系忙,只能等待事務A提交。不僅插入 age = 10 的記錄需要等待事務A提交风宁,age<10蛹疯、10<age<30 的記錄頁無法完成,而大于等于30的記錄則不受影響饮寞,這足以解決幻讀問題了列吼。

這是有索引的情況,如果 age 不是索引列慌申,那么數(shù)據(jù)庫會為整個表加上間隙鎖理郑。所以,如果是沒有索引的話类缤,不管 age 是否大于等于30邻吭,都要等待事務A提交才可以成功插入宴霸。

總結

MySQL 的 InnoDB 引擎才支持事務,其中可重復讀是默認的隔離級別畸写。

讀未提交和串行化基本上是不需要考慮的隔離級別,前者不加鎖限制论笔,后者相當于單線程執(zhí)行千所,效率太差。

讀提交解決了臟讀問題最楷,行鎖解決了并發(fā)更新的問題待错。并且 MySQL 在可重復讀級別解決了幻讀問題,是通過行鎖和間隙鎖的組合 Next-Key 鎖實現(xiàn)的犯建。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末烛占,一起剝皮案震驚了整個濱河市忆家,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌芽卿,老刑警劉巖卸例,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異姑原,居然都是意外死亡呜舒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進店門唤殴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朵逝,“玉大人,你說我怎么就攤上這事配名∏觯” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵没陡,是天一觀的道長索赏。 經(jīng)常有香客問我,道長埃儿,這世上最難降的妖魔是什么融涣? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮剃斧,結果婚禮上忽你,老公的妹妹穿的比我還像新娘。我一直安慰自己根蟹,他們只是感情好糟秘,可當我...
    茶點故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布尿赚。 她就那樣靜靜地躺著沛婴,像睡著了一般督赤。 火紅的嫁衣襯著肌膚如雪泻蚊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天没卸,我揣著相機與錄音秒旋,去河邊找鬼。 笑死煤蚌,一個胖子當著我的面吹牛细卧,可吹牛的內容都是我干的。 我是一名探鬼主播贪庙,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼止邮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了屈扎?” 一聲冷哼從身側響起撩匕,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤滑沧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后哩牍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體令漂,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡丸边,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年妹窖,在試婚紗的時候發(fā)現(xiàn)自己被綠了收叶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖澄峰,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情绸硕,我是刑警寧澤魂毁,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布漱牵,位于F島的核電站,受9級特大地震影響酣胀,放射性物質發(fā)生泄漏。R本人自食惡果不足惜甚脉,卻給世界環(huán)境...
    茶點故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一牺氨、第九天 我趴在偏房一處隱蔽的房頂上張望墩剖。 院中可真熱鬧,春花似錦岭皂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猾昆。三九已至骡苞,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亚铁。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工螟加, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人然爆。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓曾雕,卻偏偏與公主長得像助被,于是被迫代替她去往敵國和親剖张。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內容