我們知道SQL標(biāo)準(zhǔn)的事務(wù)隔離級別包括:讀未提交(read uncommitted)、讀提交(read committed)寺酪、可重復(fù)讀(repeatable read)舟奠、串行化(serializable)。
簡述下四個級別的含義:
- 讀未提交:一個事務(wù)還沒提交時房维,它做的變更就能被別的事務(wù)看到沼瘫。
- 讀提交(RC): 一個事務(wù)提交之后,它做的變更才會被其他事務(wù)看到咙俩。
- 可重復(fù)讀(RR): 一個事務(wù)執(zhí)行過程中看到的數(shù)據(jù)耿戚,總是跟這個事務(wù)在啟動時看到的數(shù)據(jù)是一致的。當(dāng)然在可重復(fù)讀隔離級別下阿趁,未提交變更對其他事務(wù)也是不可見的膜蛔。
- 串行化:對于同一行記錄,“寫”會加“寫鎖”脖阵,“讀”會加“讀鎖”皂股。當(dāng)出現(xiàn)讀寫鎖沖突的時候,后訪問的事務(wù)必須等前一個事務(wù)執(zhí)行完成命黔,才能繼續(xù)執(zhí)行呜呐。
數(shù)據(jù)庫的多版本并發(fā)控制(即常說的
MVCC
):
同一條記錄在數(shù)據(jù)庫系統(tǒng)中存在多個版本。
InnoDB中每個事務(wù)都有一個唯一的事務(wù)ID悍募,叫作transaction id蘑辑。它是在事務(wù)開始的時候向InnoDB事務(wù)系統(tǒng)申請的,且嚴(yán)格按照申請順序遞增坠宴。因為每個事務(wù)的id是有大小順序的洋魂。可重復(fù)讀(RR)隔離級別下喜鼓,會對當(dāng)下的數(shù)據(jù)產(chǎn)生一個快照副砍,這個快照保證了RR的特性。但是這個快照并不是真的把所有庫的數(shù)據(jù)都拷貝了一份庄岖,而是根據(jù)有著大小之分的transaction id
來確定每行數(shù)據(jù)的哪個版本在當(dāng)前事務(wù)可見豁翎。若該行數(shù)據(jù)的某個版本的transaction id
比當(dāng)前事務(wù)的transaction id
小且該版本已提交,則可見顿锰;反之不可見谨垃。
看到上圖,該行數(shù)據(jù)有四個版本硼控,分別是V1刘陶,V2,V3牢撼,V4(當(dāng)前最新版本是V4匙隔,前三個值不是真實存在的,而是通過回滾日志undo log
根據(jù)需要隨時可以通過計算獲取到的虛擬存在)熏版。此時k的最新值為22纷责,若一個事務(wù)trx_id
等于18捍掺,那么對這個事務(wù)來說,該行數(shù)據(jù)的k值就是11再膳,保證了RR級別下的一致性讀挺勿。
這里特別提醒,雖然上述例子中喂柒,trx_id
等于18的事務(wù)獲取到的k值是11不瓶,但若是trx_id
等于25的事務(wù)對k值先進(jìn)行了更新,假如設(shè)置k=100
灾杰,如果trx_id
等于18的事務(wù)中要更新k值蚊丐,那么一定是在k=100
的基礎(chǔ)上更新。
更新數(shù)據(jù)都是先讀后寫的艳吠,而這個讀麦备,只能讀當(dāng)前的值,稱為“當(dāng)前讀”(current read)昭娩。
且由于行鎖的存在凛篙,trx_id
等于18的事務(wù)會被堵住,等待trx_id
等于25的事務(wù)提交后才能更新题禀。