Mysql學(xué)習(xí)筆記:事務(wù)隔離級別

這個(gè)問題其實(shí)有很多人都已經(jīng)教科書式的總結(jié)了很多遍,如:

隔離級別 中文描述 此級別問題(面試官喜歡用這個(gè))
READ UNCOMMITED 未提交讀 臟讀
READ COMMITED 提交讀 不可重復(fù)讀
REPEATABLE READ 可重復(fù)讀 幻讀
SERIALIZABLE 串行化

但是在這個(gè)表格中最后一列的問題因何產(chǎn)生,很多人會(huì)不明白其中的緣由。我先說下我的理解,然后再來一點(diǎn)點(diǎn)解釋:

事務(wù)隔離的四個(gè)級別可以先用“事務(wù)是否可并發(fā)”來劃分成兩個(gè)對立面來理解:

  1. 事務(wù)不可并發(fā)在 Mysql 中只有 SERIALIZABLE 這一級別滿足;其它的當(dāng)然是事務(wù)可并發(fā)了;
  2. 事務(wù)不可并發(fā),Mysql 選擇了串行化這一實(shí)現(xiàn)方式,因此引入了鎖,也帶來了性能問題;
  3. 事務(wù)可并發(fā),因此在多個(gè)并發(fā)的事務(wù)期間,我們并不知道哪個(gè)事務(wù)的哪段邏輯(begin/rollback/commit)會(huì)在下一個(gè)時(shí)間片內(nèi)被執(zhí)行;

并發(fā)事務(wù)帶來的問題

在上面的描述中,2、3是對1的一個(gè)擴(kuò)展,2不難理解,但是 3 可能有些生硬,我們可以簡單的換種理解方式,

  1. 假設(shè)同一時(shí)間有兩個(gè)事務(wù): A & B,并且事務(wù) A 執(zhí)行 update,事務(wù) B 執(zhí)行 select。
  2. 假設(shè)事務(wù)的開啟、提交、回滾及事務(wù)中執(zhí)行的 Action 都能在一個(gè) cpu 時(shí)間片內(nèi)完成,那么可把 A&B 的事務(wù)拆成如下邏輯調(diào)用段:
# 事務(wù)A 事務(wù)B
1 begin begin
2 update select
3 commit commit
4 rollback rollback

基于上面的假設(shè),我們再來理解事務(wù)并發(fā)情況下各種問題的產(chǎn)生:

臟讀

  1. A begin => update 后讓 cpu
  2. 同時(shí)B begin => select,但是事務(wù) B 很心大,并沒有去驗(yàn)證 A 的有效性,讀到了 A update 后的數(shù)據(jù);
  3. A 在下一個(gè) cpu 時(shí)間又得到了調(diào)度,A 發(fā)現(xiàn)自己剛才的操作無效了,A rollback 得到了執(zhí)行,但是它無法告知 B 了,所以 B 讀到的數(shù)據(jù)是無效的;

不可重復(fù)讀

知道了臟讀的原因后,為了解決這個(gè)問題,Mysql 規(guī)定 B 讀的數(shù)據(jù)只能讀取已經(jīng) commit 狀態(tài)的數(shù)據(jù):

  1. A begin => update 后讓 cpu
  2. 同時(shí) B begin => select,這次 B 很小心地驗(yàn)證 A 的數(shù)據(jù)是否 commit 了,B 這次讀到了 A begin 以前的數(shù)據(jù);
  3. 事務(wù) A 在下一個(gè) cpu 時(shí)間又得到了調(diào)度,A commit 了;
  4. B 再次 select,但是已經(jīng) select 到了 A commit 后的數(shù)據(jù)了,B 在 A commit 前后讀到了兩次不一樣的數(shù)據(jù),即不可重復(fù)讀了;

幻讀

知道了不可重復(fù)讀的原因后,Mysql 又規(guī)定,既然 B 第一次讀到的是 A commit 前的數(shù)據(jù),那么在事務(wù) B 中后面無論多少次 select 都只能讀到 A commit 之前的數(shù)據(jù)。但是問題又來了:

  1. 這次 A 不是 update 了,而是 insert,B select 也不是單條了,而是 select range;
  2. B 在 A commit 前后兩次 select range 會(huì)發(fā)現(xiàn)結(jié)果的數(shù)量不一至;這就是幻讀;

InnoDB 針對幻讀也做了處理:MVCC,在每一行后都有隱藏的兩列版本號來實(shí)現(xiàn);大致與處理不可重復(fù)讀相同;

不可并發(fā)帶來的問題

Mysql 用串行來實(shí)現(xiàn)不可并發(fā),雖說是串行,但是要保證事務(wù)被正確的放入串行隊(duì)列中,就會(huì)引入鎖等機(jī)制,增加了開銷,所以非不得已,將不會(huì)使用此級別。

三歲于辛 的博客《Mysql學(xué)習(xí)筆記:事務(wù)隔離級別

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容