Mysql事務(wù)

Mysql事務(wù)

Mysql事務(wù)簡介

**

Mysql的事務(wù):

數(shù)據(jù)庫的事務(wù)是指一組sql語句組成的數(shù)據(jù)庫邏輯處理單元,在這組的sql操作中,要么全部執(zhí)行成功满败,要么全部執(zhí)行失敗藏雏。

這里的一組sql操作,舉個簡單又經(jīng)典的例子就是轉(zhuǎn)賬了肌稻,事務(wù)A中要進行轉(zhuǎn)賬,那么轉(zhuǎn)出的賬號要扣錢匕荸,轉(zhuǎn)入的賬號要加錢爹谭,這兩個操作都必須同時執(zhí)行成功,為了確保數(shù)據(jù)的一致性榛搔。

事務(wù)的特性:

ACID簡介

在Mysql中事務(wù)的四大特性主要包含:原子性(Atomicity)旦棉、一致性(Consistent)齿风、隔離性(Isalotion)、持久性(Durable)绑洛,簡稱為ACID救斑。

原子性是指事務(wù)的原子性操作,對數(shù)據(jù)的修改要么全部執(zhí)行成功真屯,要么全部失敗脸候,實現(xiàn)事務(wù)的原子性,是基于日志的Redo/Undo機制绑蔫。

一致性是指執(zhí)行事務(wù)前后的狀態(tài)要一致运沦,可以理解為數(shù)據(jù)一致性。

隔離性側(cè)重指事務(wù)之間相互隔離配深,不受影響携添,這個與事務(wù)設(shè)置的隔離級別有密切的關(guān)系。

持久性則是指在一個事務(wù)提交后篓叶,這個事務(wù)的狀態(tài)會被持久化到數(shù)據(jù)庫中烈掠,也就是事務(wù)提交,對數(shù)據(jù)的新增缸托、更新將會持久化到數(shù)據(jù)庫中左敌。

原子性、隔離性俐镐、持久性都是為了保障一致性而存在的矫限,一致性也是最終的目的。

ACID原理

**

Redo/Undo機制:

Redo/Undo機制比較簡單佩抹,它們將所有對數(shù)據(jù)的更新操作都寫到日志中叼风。

Redo log用來記錄某數(shù)據(jù)塊被修改后的值,可以用來恢復(fù)未寫入 data file 的已成功事務(wù)更新的數(shù)據(jù)棍苹;Undo log是用來記錄數(shù)據(jù)更新前的值无宿,保證數(shù)據(jù)更新失敗能夠回滾。

假如數(shù)據(jù)庫在執(zhí)行的過程中廊勃,不小心崩了,可以通過該日志的方式经窖,回滾之前已經(jīng)執(zhí)行成功的操作坡垫,實現(xiàn)事務(wù)的一致性。

場景:

假如某個時刻數(shù)據(jù)庫崩潰画侣,在崩潰之前有事務(wù)A和事務(wù)B在執(zhí)行冰悠,事務(wù)A已經(jīng)提交,而事務(wù)B還未提交配乱。當(dāng)數(shù)據(jù)庫重啟進行 crash-recovery 時溉卓,就會通過Redo log將已經(jīng)提交事務(wù)的更改寫到數(shù)據(jù)文件皮迟,而還沒有提交的就通過Undo log進行roll back。

事務(wù)隔離級別

**

事務(wù)的隔離級別:

在Mysql中事務(wù)的隔離級別分為四大等級桑寨,讀未提交(READ UNCOMMITTED)伏尼、讀已提交 (READ COMMITTED)、可重復(fù)讀 (REPEATABLE READ)尉尾、順序讀(SERIALIZABLE)爆阶。

1599377934739.png

讀未提交會讀到另一個事務(wù)的未提交的數(shù)據(jù),產(chǎn)生臟讀問題沙咏,讀已提交則解決了臟讀的辨图,出現(xiàn)了不可重復(fù)讀,即在一個事務(wù)任意時刻讀到的數(shù)據(jù)可能不一樣肢藐,可能會受到其它事務(wù)對數(shù)據(jù)修改提交后的影響故河,一般是對于update的操作。

可重復(fù)讀解決了之前不可重復(fù)讀和臟讀的問題吆豹,但是由帶來了幻讀的問題鱼的,幻讀一般是針對inser操作。

例如:第一個事務(wù)查詢一個User表id=100發(fā)現(xiàn)不存在該數(shù)據(jù)行瞻讽,這時第二個事務(wù)又進來了鸳吸,新增了一條id=100的數(shù)據(jù)行并且提交了事務(wù)。

這時第一個事務(wù)新增一條id=100的數(shù)據(jù)行會報主鍵沖突速勇,第一個事務(wù)再select一下晌砾,發(fā)現(xiàn)id=100數(shù)據(jù)行已經(jīng)存在,這就是幻讀烦磁。

演示:

創(chuàng)建一個User表养匈,做為一個測試表,測試表里面有三個字段都伪,并插入兩條測試數(shù)據(jù)呕乎。

CREATE TABLE User (  id INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,  name VARCHAR(20),  age INT  DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=gb2312;INSERT INTO `user` VALUES (1, 'zhangsan', 23);INSERT INTO `user` VALUES (2, 'lisi', 20);

在Mysql中可以先查詢一下他的默認隔離級別,可以看出Mysql的默認隔離級別是可重復(fù)讀REPEATABLE-READ陨晶。

image.png

讀未提交:先把默認的隔離級別修改為READ UNCOMMITTED猬仁。

image.png

設(shè)置隔離級別的語句中set global transaction isolation level read uncommitted,這里的global也可以換成session先誉,global表示全局的湿刽,而session表示當(dāng)前會話,也就是當(dāng)前窗口有效褐耳。

當(dāng)設(shè)置完隔離級別后對于之前打開的會話诈闺,是無效的,要重新打開一個窗口設(shè)置隔離級別才生效铃芦。

image.png

然后是開啟事務(wù)雅镊,Mysql中開啟事務(wù)有兩種方式begin/start transaction襟雷,最后提交事務(wù)執(zhí)行commit,或者回滾事務(wù)rollback仁烹。

在執(zhí)行begin/start transaction命令耸弄,它們并不是一個事務(wù)的起點,在執(zhí)行完它們后的第一個sql語句晃危,才表示事務(wù)真正的啟動 叙赚。

這里直接打開兩個新的窗口,同時開啟事務(wù)僚饭,在第一個窗口先update一個id=1的數(shù)據(jù)行name改為'非科班的科班'震叮,執(zhí)行成功。

image.png

然后再第二個窗口執(zhí)行兩次的查詢鳍鸵,分別是窗口一update之前的查詢和update之后的查詢苇瓣。

image.png

第一個session產(chǎn)生的未提交的事務(wù)的狀態(tài)就會直接影響到第二sesison,也就是臟讀偿乖。

對于讀提交也是一樣的击罪,開啟事務(wù)后,第一個事務(wù)先執(zhí)行查詢數(shù)據(jù)贪薪,然后第二個session執(zhí)行update操作媳禁,但是還沒有commit,這時第一個session再次select画切,數(shù)據(jù)并沒有改變竣稽,再第二個session執(zhí)行commit之后,第一個session再次select就是改變后的數(shù)據(jù)了霍弹。

image.png

這樣第一個事務(wù)的查詢結(jié)果就會收到第二事務(wù)的影響毫别,這個也就是產(chǎn)生不可重復(fù)讀的問題。

過程圖:

image.png

這個是讀提交的時間軸圖典格,讀未提交的時間軸圖岛宦,原理也一樣的,第二個select的時候數(shù)據(jù)就已經(jīng)改變了耍缴。

可重復(fù)讀:

image.png

將兩個session開啟為REPEATABLE READ砾肺,同時開啟事務(wù),在第一個事務(wù)中先select防嗡,然后在第二個事務(wù)里面update數(shù)據(jù)行变汪,可以發(fā)現(xiàn)即使第二個事務(wù)已經(jīng)commit,第一個事務(wù)再次select數(shù)據(jù)也還是沒有改變本鸣,這就解決了不可重復(fù)讀的問題疫衩。

這里有個不同的地方就是在Mysql中硅蹦,默認的不可重復(fù)讀個隔離級別也解決了幻讀的問題荣德。

從上面的演示中可以看出第一個事務(wù)中先select一個id=3的數(shù)據(jù)行闷煤,這條數(shù)據(jù)行是不存在的,返回Empty set涮瞻,然后第二個事務(wù)中insert一條id=3的數(shù)據(jù)行并且commit鲤拿,第一個事務(wù)中再次select的,數(shù)據(jù)也好是沒有id=3的數(shù)據(jù)行署咽。

最后的順序讀近顷,樣式步驟也是一樣的,結(jié)果也和Mysql中默認的個可重復(fù)讀隔離級別的結(jié)果一樣宁否,順序讀的執(zhí)行流程相當(dāng)于把事務(wù)的執(zhí)行過程變?yōu)轫樞驁?zhí)行窒升。

這四大等級從上到下,隔離的效果是逐漸增強慕匠,但是性能卻是越來越差饱须。

Mysql的鎖機制

**

為什么會性能越來越差?

這個得從Mysq的鎖說起台谊,在Mysql中的鎖可以分為分享鎖/讀鎖(Shared Locks)蓉媳、排他鎖/寫鎖(Exclusive Locks) 、間隙鎖锅铅、行鎖(Record Locks)酪呻、表鎖。

在四個隔離級別中加鎖肯定是要消耗性能的盐须,而讀未提交是沒有加任何鎖的玩荠,所以對于它來說也就是沒有隔離的效果,所以它的性能也是最好的丰歌。

對于順序讀加的是一把大鎖姨蟋,讀的時候加共享鎖,不能寫立帖,寫的時候眼溶,加的是排它鎖,阻塞其它事務(wù)的寫入和讀取晓勇,若是其它的事務(wù)長時間不能寫入就會直接報超時堂飞,所以它的性能也是最差的,對于它來就沒有什么并發(fā)性可言绑咱。

對于讀提交和可重復(fù)讀绰筛,他們倆的實現(xiàn)是兼顧解決數(shù)據(jù)問題,然后又要有一定的并發(fā)行描融,所以在實現(xiàn)上鎖機制會比串行化優(yōu)化很多铝噩,提高并發(fā)性,所以性能也會比較好窿克。

事務(wù)底層實現(xiàn)原理

**

他們倆的底層實現(xiàn)采用的是MVCC(多版本并發(fā)控制)方式進行實現(xiàn)骏庸。

這幾個鎖的概念:

共享鎖是針對同一份數(shù)據(jù)毛甲,多個讀操作可以同時進行,簡單來說即讀加鎖具被,不能寫并且可并行讀玻募;排他鎖針對寫操作,假如當(dāng)前寫操作沒有完成一姿,那么它會阻斷其它的寫鎖和讀鎖七咧,即寫加鎖,其它讀寫都阻塞 叮叹。

而行鎖和表鎖艾栋,是從鎖的粒度上進行劃分的,行鎖鎖定當(dāng)前數(shù)據(jù)行蛉顽,鎖的粒度小裹粤,加鎖慢,發(fā)生鎖沖突的概率小蜂林,并發(fā)度高遥诉,行鎖也是MyISAM和InnoDB的區(qū)別之一,InnoDB支持行鎖并且支持事務(wù) 噪叙。

而表鎖則鎖的粒度大矮锈,加鎖快,開銷小睁蕾,但是鎖沖突的概率大苞笨,并發(fā)度低。

間隙鎖則分為兩種:Gap Locks和Next-Key Locks子眶。Gap Locks會鎖住兩個索引之間的區(qū)間瀑凝,比如select * from User where id>3 and id<5 for update,就會在區(qū)間(3臭杰,5)之間加上Gap Locks粤咪。

Next-Key Locks是Gap Locks+Record Locks(行鎖)形成閉區(qū)間鎖select * from User where id>=3 and id=<5 for update,就會在區(qū)間[3,5]之間加上Next-Key Locks渴杆。

Mysql中什么時候會加鎖呢寥枝?

在數(shù)據(jù)庫的增、刪磁奖、改囊拜、查中,只有增比搭、刪冠跷、改才會加上排它鎖,而只是查詢并不會加鎖,只能通過在select語句后顯式加lock in share mode或者for update來加共享鎖或者排它鎖蜜托。

MVCC(多版本并發(fā)控制)原理:

在實現(xiàn)MVCC時用到了一致性視圖弟疆,用于支持讀已提交和可重復(fù)讀的實現(xiàn)。

在實現(xiàn)可重復(fù)讀的隔離級別盗冷,只需要在事務(wù)開始的時候創(chuàng)建一致性視圖,也叫做快照同廉,之后的查詢里都共用這個一致性視圖仪糖,后續(xù)的事務(wù)對數(shù)據(jù)的更改是對當(dāng)前事務(wù)是不可見的,這樣就實現(xiàn)了可重復(fù)讀迫肖。

而讀已提交锅劝,每一個語句執(zhí)行前都會重新計算出一個新的視圖,這個也是可重復(fù)讀和讀已提交在MVCC實現(xiàn)層面上的區(qū)別蟆湖。

快照(視圖)在MVCC底層是怎么工作的:

在InnoDB 中每一個事務(wù)都有一個自己的事務(wù)id故爵,并且是唯一的,遞增的 隅津。

對于Mysql中的每一個數(shù)據(jù)行都有可能存在多個版本诬垂,在每次事務(wù)更新數(shù)據(jù)的時候,都會生成一個新的數(shù)據(jù)版本伦仍,并且把自己的數(shù)據(jù)id賦值給當(dāng)前版本的row trx_id结窘。

image.png

如圖中所示,假如三個事務(wù)更新了同一行數(shù)據(jù)充蓝,那么就會有對應(yīng)的三個數(shù)據(jù)版本隧枫。

實際上版本1、版本2并非實際物理存在的谓苟,而圖中的U1和U2實際就是undo log官脓,這v1和v2版本是根據(jù)當(dāng)前v3和undo log計算出來的。

對于一個快照來說涝焙,需要遵循什么規(guī)則:

對于一個事務(wù)視圖來說除了對自己更新的總是可見卑笨,另外還有三種情況:版本未提交的,都是不可見的仑撞;版本已經(jīng)提交湾趾,但是是在創(chuàng)建視圖之后提交的也是不可見的;版本已經(jīng)提交派草,若是在創(chuàng)建視圖之前提交的是可見的搀缠。

假如兩個事務(wù)執(zhí)行寫操作,怎么保證并發(fā):

假如事務(wù)1和事務(wù)2都要執(zhí)行update操作近迁,事務(wù)1先update數(shù)據(jù)行的時候艺普,先回獲取行鎖,鎖定數(shù)據(jù),當(dāng)事務(wù)2要進行update操作的時候歧譬,也會取獲取該數(shù)據(jù)行的行鎖岸浑,但是已經(jīng)被事務(wù)1占有,事務(wù)2只能wait瑰步。

若是事務(wù)1長時間沒有釋放鎖矢洲,事務(wù)2就會出現(xiàn)超時異常 。

這個是在update的where后的條件是在有索引的情況下

沒有索引的條件下:

若是沒有索引的條件下缩焦,就獲取所有行读虏,都加上行鎖,然后Mysql會再次過濾符合條件的的行并釋放鎖袁滥,只有符合條件的行才會繼續(xù)持有鎖盖桥。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市题翻,隨后出現(xiàn)的幾起案子揩徊,更是在濱河造成了極大的恐慌,老刑警劉巖嵌赠,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件塑荒,死亡現(xiàn)場離奇詭異,居然都是意外死亡姜挺,警方通過查閱死者的電腦和手機袜炕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來初家,“玉大人偎窘,你說我怎么就攤上這事×镌冢” “怎么了陌知?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掖肋。 經(jīng)常有香客問我仆葡,道長,這世上最難降的妖魔是什么志笼? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任沿盅,我火速辦了婚禮初澎,結(jié)果婚禮上燎悍,老公的妹妹穿的比我還像新娘。我一直安慰自己犯祠,他們只是感情好紊浩,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布窖铡。 她就那樣靜靜地躺著疗锐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪费彼。 梳的紋絲不亂的頭發(fā)上滑臊,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天,我揣著相機與錄音箍铲,去河邊找鬼雇卷。 笑死,一個胖子當(dāng)著我的面吹牛颠猴,可吹牛的內(nèi)容都是我干的关划。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼芙粱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了氧映?” 一聲冷哼從身側(cè)響起春畔,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岛都,沒想到半個月后律姨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡臼疫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年择份,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烫堤。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡荣赶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸽斟,到底是詐尸還是另有隱情拔创,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布富蓄,位于F島的核電站剩燥,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏立倍。R本人自食惡果不足惜灭红,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望口注。 院中可真熱鬧变擒,春花似錦、人聲如沸寝志。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至悠菜,卻和暖如春舰攒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悔醋。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工摩窃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人芬骄。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓猾愿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親账阻。 傳聞我的和親對象是個殘疾皇子蒂秘,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355