事務(wù)的原理、MVCC的原理

事務(wù)特性

數(shù)據(jù)庫事務(wù)具有以下四個基本特性,通常被稱為 ACID 特性:

  1. 原子性(Atomicity):事務(wù)被視為不可分割的最小工作單元叙凡,要么全部執(zhí)行成功劈伴,要么全部失敗回滾。這意味著如果事務(wù)執(zhí)行過程中發(fā)生了錯誤握爷,所有的修改都將被回滾跛璧,數(shù)據(jù)庫狀態(tài)將回到事務(wù)執(zhí)行前的狀態(tài)。

  2. 一致性(Consistency):事務(wù)執(zhí)行前后新啼,數(shù)據(jù)庫從一個一致性狀態(tài)轉(zhuǎn)換到另一個一致性狀態(tài)追城。事務(wù)的執(zhí)行不會破壞數(shù)據(jù)庫的完整性約束,例如主鍵燥撞、外鍵約束等座柱。數(shù)據(jù)庫會保持?jǐn)?shù)據(jù)的完整性和一致性迷帜。

  3. 隔離性(Isolation):每個事務(wù)的操作都相互隔離,一個事務(wù)的中間結(jié)果對其他事務(wù)是不可見的色洞。這意味著一個事務(wù)的修改在提交之前對其他事務(wù)是不可見的戏锹,防止了并發(fā)事務(wù)之間的相互影響,保證了數(shù)據(jù)的正確性火诸。

  4. 持久性(Durability):一旦事務(wù)提交成功锦针,對數(shù)據(jù)庫的修改就會永久保存,即使系統(tǒng)故障或崩潰也不會丟失置蜀。數(shù)據(jù)庫會將事務(wù)的結(jié)果持久化到非易失性存儲器中奈搜,以保證即使系統(tǒng)發(fā)生故障,數(shù)據(jù)也不會丟失盯荤。

這些特性確保了數(shù)據(jù)庫事務(wù)的可靠性和穩(wěn)定性馋吗。它們是數(shù)據(jù)庫管理系統(tǒng)中設(shè)計用于支持可靠性和并發(fā)控制的重要概念。通過保證事務(wù)具有這些特性廷雅,數(shù)據(jù)庫可以提供穩(wěn)定耗美、可靠、高效的數(shù)據(jù)管理和處理能力航缀。

事務(wù)的隔離級別

事務(wù)的隔離性

事務(wù)完全的串行會嚴(yán)重的降低系統(tǒng)的吞吐量和資源利用率商架,仔細(xì)發(fā)現(xiàn),引發(fā)事務(wù)一致性問題的根本原因在于多個事務(wù)訪問了相同的數(shù)據(jù)芥玉,更合理的做法是蛇摸,在某個事務(wù)訪問某個數(shù)據(jù)時,對其他想要訪問該數(shù)據(jù)的事務(wù)進(jìn)行限制灿巧,當(dāng)該事務(wù)提交后赶袄,其他事務(wù)才能繼續(xù)訪問這個數(shù)據(jù)

事務(wù)并發(fā)執(zhí)行引發(fā)的一致性問題

臟讀

一個事務(wù)讀取了另一個未提交事務(wù)修改過的數(shù)據(jù),意味著發(fā)生了臟讀抠藕,臟讀引發(fā)的事務(wù)一致性問題饿肺。T1事務(wù)讀取了T2事務(wù)未提交的數(shù)據(jù)。
幻讀和不可重復(fù)讀是并發(fā)事務(wù)中可能出現(xiàn)的兩種問題盾似,它們在數(shù)據(jù)庫事務(wù)隔離級別較低的情況下會更容易發(fā)生敬辣。它們之間的區(qū)別在于以下幾點:

幻讀(Phantom Read)

幻讀指的是在同一個事務(wù)內(nèi)多次執(zhí)行同樣的查詢,但在查詢中返回了不同的數(shù)據(jù)行的現(xiàn)象零院。這種情況通常發(fā)生在一個事務(wù)中插入數(shù)據(jù)后溉跃,另一個并發(fā)事務(wù)再執(zhí)行相同的查詢,發(fā)現(xiàn)結(jié)果集中出現(xiàn)了之前不存在的行告抄。

不可重復(fù)讀(Non-repeatable Read)

不可重復(fù)讀指的是在同一個事務(wù)內(nèi)多次執(zhí)行同樣的查詢撰茎,但在查詢中返回了不同的數(shù)據(jù)行的現(xiàn)象。與幻讀不同的是打洼,不可重復(fù)讀是由于其他并發(fā)事務(wù)對數(shù)據(jù)進(jìn)行了修改導(dǎo)致的龄糊。

總的來說逆粹,幻讀側(cè)重于事務(wù)在查詢中發(fā)現(xiàn)了之前不存在的數(shù)據(jù)行,而不可重復(fù)讀側(cè)重于事務(wù)在多次讀取相同數(shù)據(jù)時發(fā)現(xiàn)數(shù)據(jù)被其他事務(wù)修改绎签。兩者的根本區(qū)別在于幻讀關(guān)注的是新增或者刪除的數(shù)據(jù)行枯饿,而不可重復(fù)讀關(guān)注的是已經(jīng)存在的數(shù)據(jù)行發(fā)生了改變

SQL標(biāo)準(zhǔn)中的四種隔離級別

設(shè)置隔離級別的目的是诡必,舍棄一部分隔離性換取一部分性能奢方,SQL標(biāo)準(zhǔn)中的4個隔離級別:

隔離級別 臟讀 不可重復(fù)讀 幻讀
READ UNCOMMITTED 允許 允許 允許
READ COMMITTED 不允許 允許 允許
REPEATABLE READ 不允許 不允許 允許
SERIALIZABLE 不允許 不允許 不允許

MySQL中支持的4中隔離級別

MySQL中的默認(rèn)隔離級別是:REPEATABLE READ
MySQL8查詢事務(wù)隔離級別

SELECT @@GLOBAL.transaction_isolation;

修改隔離級別語句

set [global | session] transaction isolation level 隔離級別;

各種隔離級別適用的場景

  1. READ UNCOMMITTED (讀未提交): 這個隔離級別適用于某些特定的報表查詢場景,對數(shù)據(jù)的實時性要求非常高爸舒,而對數(shù)據(jù)一致性要求較低蟋字。例如,在某些實時監(jiān)控系統(tǒng)中扭勉,可以使用讀未提交隔離級別來獲取最新的數(shù)據(jù)鹊奖,即使數(shù)據(jù)可能尚未被完全提交。

  2. READ COMMITTED (讀已提交): 這個隔離級別適用于大多數(shù)在線交易處理系統(tǒng)(OLTP),如電子商務(wù)網(wǎng)站。在這種場景下茄菊,用戶只需要讀取已經(jīng)提交的數(shù)據(jù),以避免看到其他事務(wù)未提交的數(shù)據(jù)两蟀。一個典型的例子是在線購物系統(tǒng)中的庫存管理,確保每個用戶看到的庫存數(shù)據(jù)是準(zhǔn)確的震缭。

  3. REPEATABLE READ (可重復(fù)讀): 這個隔離級別適用于某些需要對數(shù)據(jù)進(jìn)行長時間讀取或計算的場景赂毯,比如報表生成或復(fù)雜的分析。在這些情況下拣宰,確保事務(wù)在執(zhí)行期間不受其他事務(wù)的影響是非常重要的党涕,以避免數(shù)據(jù)不一致性。例如巡社,某些財務(wù)報表的生成過程中膛堤,需要保證數(shù)據(jù)的完整性和一致性。

  4. SERIALIZABLE (可串行化): 這個隔離級別適用于某些極端要求數(shù)據(jù)完全一致性的場景晌该,如金融交易系統(tǒng)肥荔。在這種系統(tǒng)中,任何數(shù)據(jù)的不一致性都可能導(dǎo)致嚴(yán)重的后果气笙。因此次企,確保所有事務(wù)按順序逐個執(zhí)行是至關(guān)重要的怯晕,即使在高并發(fā)情況下也要保證數(shù)據(jù)的完整性潜圃。

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

版本鏈

在InnoDB存儲引擎中的表,聚簇索引中的記錄都包含兩個隱藏列舟茶,
trx_id:一個事務(wù)都某條聚簇索引記錄進(jìn)行修改時谭期,都會把該事務(wù)的事務(wù)id賦值給trx_id
roll_pointer:每次對聚簇索引記錄進(jìn)行改動時堵第,都會把舊的版本寫入到undo日志中,相當(dāng)于一個指針隧出,通過它可以找到該記錄修改前的信息

image.png

ReadView(讀視圖)

用READ UNCOMMITTED 隔離級別的事務(wù)來說踏志,可以讀取未提交事務(wù)修改的記錄,因此直接讀取版本鏈中的最新版本就可以了胀瞪;對于SERIALIZABLE隔離級別的事務(wù)來說针余,InnoDB中使用加鎖的方式訪問記錄,對于READ COMMITED和REPEATABLE READ隔離級別的事務(wù)來說凄诞,都必須保證讀到的記錄是已經(jīng)提交的事務(wù)修改過的記錄圆雁,因此核心問題就是:需要判斷版本鏈中的哪個版本對于當(dāng)前事務(wù)是可見的,InnoDB給出的解決方案是帆谍,生成ReadView伪朽,ReadView包含下列四個重要內(nèi)容:

m_ids:生成ReadView時,當(dāng)前系統(tǒng)中活躍的事務(wù)id列表

min_trx_id:m_ids中的最小事務(wù)id

max_trx_id:在生成ReadView時汛蝙,系統(tǒng)分配個下一個事務(wù)的事務(wù)id(max_trx_id+1)

creator_trx_id:生成該ReadView的事務(wù)的事務(wù)id

生成了ReadView之后烈涮,我們就可以借助它來判斷當(dāng)前版本的記錄對當(dāng)前事務(wù)是否可見:

  • 如果當(dāng)前記錄的trx_id與creator_trx_id相同,意味著當(dāng)前事務(wù)在訪問自己修改過的記錄窖剑,可以訪問
  • 如果當(dāng)前記錄的trx_id小于min_trx_id坚洽,說明生成該版本記錄的事務(wù)已經(jīng)提交了,可以訪問
  • 如果當(dāng)前記錄的trx_id 大于max_trx_id苛吱,說明生成該版本的事務(wù)在當(dāng)前事務(wù)生成ReadView之后才開啟酪术,所以該版本不可以被當(dāng)前事務(wù)訪問
  • 如果被訪問版本的trx_id 在 min_trx_id 和 max_trx_id之間,則需進(jìn)一步判斷trx_id是否在m_ids列表中翠储,如果在說明事務(wù)為提交绘雁,該版本不可見,如果不在援所,說明可見

在MySQL中庐舟,READ COMMITED和REPEATABLE READ 隔離級別之間一個非常答的區(qū)別就是他們生成ReadView的時機不同

READ COMMITED 每次讀取數(shù)據(jù)前都生成一個ReadView

例如,現(xiàn)在系統(tǒng)中有兩個事務(wù)id為T100住拭,T200的事務(wù)正在執(zhí)行挪略,T80是已經(jīng)提交的事務(wù)。100的事務(wù)修改a=1,200的事務(wù)修改a=2,下面是表信息滔岳,其中第一行索引中的記錄杠娱。

id a trx_id roll_point
1 1 100 100
1 1 100 80
1 0 80

假設(shè)現(xiàn)在有一個使用READ COMMITED隔離級別的新事物開始執(zhí)行:
執(zhí)行語句為

select a from t where id=1;

select語句執(zhí)行過程如下:

  • 執(zhí)行select語句時生成一個ReadView,m_ids列表為[100,200]谱煤,min_trx_id為100摊求,max_trx_id為201,creator_trx_id為0

因為這個新開啟的事務(wù)只進(jìn)行了select操作刘离,并沒有對記錄進(jìn)行修改室叉,所以系統(tǒng)沒有為其分配事務(wù)id睹栖,默認(rèn)為0

  • 順序版本鏈尋找符合要求的版本,返回的是a為"0"的版本

之后茧痕,將事務(wù)id為100的事務(wù)提交事務(wù) 200 事務(wù)中更新表 hero number 的記錄

update t set a = "2" where id=1

然后再到剛才使用 READ COMMITTED隔離級別的事務(wù)執(zhí)行select語句野来,繼續(xù)查找number為1 的記錄,執(zhí)行步驟如下:

  • 生成ReadView踪旷,m_ids列表[200]曼氛,min_trx_id為200,max_trx_id為200令野,creator_trx_id為0
  • 順序版本鏈搪锣,查找符合要求的版本,最終返回的是"1"

REPEATABLE 在第一次讀取數(shù)據(jù)時生成一個ReadView

假設(shè)現(xiàn)在有一個使用 REPEATABLE READ 隔離級別的新事務(wù)開始執(zhí)行:
第一次select操作時:

  • 生成ReadView彩掐,執(zhí)行select語句時生成一個ReadView构舟,m_ids列表為[100,200],min_trx_id為100堵幽,max_trx_id為201狗超,creator_trx_id為0
  • 找到符合條件的版本"0"

之后將事務(wù)id為100的事務(wù)提交后,再到事務(wù)id為200的事務(wù)中更新表中id為1的記錄
然后再次執(zhí)行select:

  • 沿用(或者說復(fù)制)第一次select時生成的ReadView
  • 最終的返回版本還是"0"

總結(jié)朴下,在REPEATABLE READ隔離級別下努咐,事務(wù)的兩次查詢結(jié)果是一樣的,因此可以說在REPEATABLE READ級別下避免了不可重復(fù)讀的發(fā)生殴胧,同時也很大程度上避免了幻讀的發(fā)生

MVCC小結(jié)

所謂的MVCC指的就是在使用READ COMMITED 和 REPEATABLE READ這兩種隔離級別的事務(wù)在執(zhí)行select操作時渗稍,訪問記錄版本鏈的過程,這樣可以使不同事務(wù)的讀-寫操作并發(fā)執(zhí)行团滥,從而提升系統(tǒng)性能竿屹。READ COMMITED 和 REPEATABLE READ的最大區(qū)別在于,生成Read View的時機不同灸姊,READ COMMITED 每次執(zhí)行select前都會生成一個新的ReadView拱燃,而REPEATABLE READ只在第一次執(zhí)行select前生成一個ReadView

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市力惯,隨后出現(xiàn)的幾起案子碗誉,更是在濱河造成了極大的恐慌,老刑警劉巖父晶,帶你破解...
    沈念sama閱讀 212,542評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哮缺,死亡現(xiàn)場離奇詭異,居然都是意外死亡甲喝,警方通過查閱死者的電腦和手機尝苇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茎匠,你說我怎么就攤上這事⊙号郏” “怎么了诵冒?”我有些...
    開封第一講書人閱讀 158,021評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長谊惭。 經(jīng)常有香客問我汽馋,道長,這世上最難降的妖魔是什么圈盔? 我笑而不...
    開封第一講書人閱讀 56,682評論 1 284
  • 正文 為了忘掉前任豹芯,我火速辦了婚禮,結(jié)果婚禮上驱敲,老公的妹妹穿的比我還像新娘铁蹈。我一直安慰自己,他們只是感情好众眨,可當(dāng)我...
    茶點故事閱讀 65,792評論 6 386
  • 文/花漫 我一把揭開白布握牧。 她就那樣靜靜地躺著,像睡著了一般娩梨。 火紅的嫁衣襯著肌膚如雪沿腰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,985評論 1 291
  • 那天狈定,我揣著相機與錄音颂龙,去河邊找鬼。 笑死纽什,一個胖子當(dāng)著我的面吹牛措嵌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芦缰,決...
    沈念sama閱讀 39,107評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼铅匹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饺藤?” 一聲冷哼從身側(cè)響起包斑,我...
    開封第一講書人閱讀 37,845評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎涕俗,沒想到半個月后罗丰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡再姑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,612評論 2 327
  • 正文 我和宋清朗相戀三年萌抵,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,747評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡绍填,死狀恐怖霎桅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情讨永,我是刑警寧澤滔驶,帶...
    沈念sama閱讀 34,441評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站卿闹,受9級特大地震影響揭糕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜锻霎,卻給世界環(huán)境...
    茶點故事閱讀 40,072評論 3 317
  • 文/蒙蒙 一著角、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吏口,春花似錦、人聲如沸锨侯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至审葬,卻和暖如春深滚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痴荐。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留生兆,地道東北人。 一個月前我還...
    沈念sama閱讀 46,545評論 2 362
  • 正文 我出身青樓膝宁,卻偏偏與公主長得像鸦难,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子员淫,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,658評論 2 350

推薦閱讀更多精彩內(nèi)容