事務(wù)的 ACID 特性 與 事務(wù)的隔離級別

事務(wù)的四個特性(ACID)

如果一個數(shù)據(jù)庫聲稱支持事務(wù)的操作,那么該數(shù)據(jù)庫必須要具備以下四個特性:

  1. 原子性Atomicity)
      原子性是指事務(wù)包含的所有操作要么全部成功,要么全部失敗回滾。一旦事務(wù)在運行中出現(xiàn)錯誤,直接回滾到未啟動事務(wù)前。

  2. 一致性Consistency)
      一致性是指事務(wù)必須使數(shù)據(jù)庫從一個一致性狀態(tài)變換到另一個一致性狀態(tài),也就是說一個事務(wù)執(zhí)行之前和執(zhí)行之后都必須處于一致性狀態(tài)。多個事務(wù)并發(fā)的情況下,也要保證系統(tǒng)數(shù)據(jù)有如同串行操作一樣的一致效果。

  3. 隔離性Isolation)
      隔離性是當(dāng)多個用戶并發(fā)訪問數(shù)據(jù)庫時,數(shù)據(jù)庫為每一個用戶開啟的事務(wù),不能被其他事務(wù)的操作所干擾,多個并發(fā)事務(wù)之間要相互隔離,仿佛是系統(tǒng)內(nèi)唯一操作。
      即要達到這么一種效果:對于任意兩個并發(fā)的事務(wù) T1 和 T2,在事務(wù) T1 看來,T2 要么在 T1 開始之前就已經(jīng)結(jié)束,要么在 T1 結(jié)束之后才開始,這樣每個事務(wù)都感覺不到有其他事務(wù)在并發(fā)地執(zhí)行。

  4. 持久性Durability)
      持久性是指一個事務(wù)一旦被提交了,那么對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久性的,即便是在數(shù)據(jù)庫系統(tǒng)遇到故障的情況下也不會丟失提交事務(wù)的操作。

事務(wù)的隔離級別

先來看看如果不考慮事務(wù)的隔離性,會發(fā)生的幾種問題:

  1. 第一類丟失更新(Update Lost)
      此種更新丟失是因為回滾的原因,所以也叫回滾丟失。此時兩個事務(wù)同時更新 count,兩個事務(wù)都讀取到 100,事務(wù)一更新成功并提交,count=100+1=101,事務(wù)二出于某種原因更新失敗了,然后回滾,事務(wù)二就把 count 還原為它一開始讀到的 100,此時事務(wù)一的更新就這樣丟失了。
  2. 臟讀(Dirty Read)
      臟讀是指在一個事務(wù)處理過程中讀取了另一個未提交的事務(wù)中的數(shù)據(jù)。
      當(dāng)一個事務(wù)正在多次修改某個數(shù)據(jù),而在這個事務(wù)中這多次的修改都還未提交,這時一個并發(fā)的事務(wù)來訪問該數(shù)據(jù),就會造成兩個事務(wù)得到的數(shù)據(jù)不一致。例如:用戶 A 向用戶 B 轉(zhuǎn)賬 100 元,對應(yīng) SQL 命令如下:
update account set money=money+100 where name=’B’;    --此時 A 通知 B
update account set money=money-100 where name=’A’;

當(dāng)只執(zhí)行第一條 SQL 時,A 通知 B 查看賬戶,B 發(fā)現(xiàn)確實錢已到賬(此時即發(fā)生了臟讀),而之后無論第二條 SQL 是否執(zhí)行,只要該事務(wù)不提交,則所有操作都將回滾,那么當(dāng) B 以后再次查看賬戶時就會發(fā)現(xiàn)錢其實并沒有轉(zhuǎn)。

  1. 不可重復(fù)讀(Not Repeatable Read)
      不可重復(fù)讀是指在對于數(shù)據(jù)庫中的某個數(shù)據(jù),一個事務(wù)范圍內(nèi)多次查詢卻返回了不同的數(shù)據(jù)值,這是由于在查詢間隔,被另一個事務(wù)修改并提交了。
      不可重復(fù)讀和臟讀的區(qū)別是,臟讀是某一事務(wù)讀取了另一個事務(wù)未提交的臟數(shù)據(jù),而不可重復(fù)讀則是讀取了前一事務(wù)提交的數(shù)據(jù)。
      在某些情況下,不可重復(fù)讀并不是問題,比如我們多次查詢某個數(shù)據(jù)當(dāng)然以最后查詢得到的結(jié)果為主。但在另一些情況下就有可能發(fā)生問題,例如對于 A 和 B 依次查詢就可能不同,影響后續(xù)的操作。

  2. 第二類丟失更新(Second Update Lost)
      此種更新丟失是因為更新被其他事務(wù)給覆蓋了,也可以叫覆蓋丟失。舉個例子,兩個事務(wù)同時更新 count,都讀取 100 這個初始值,事務(wù)一先更新成功并提交,count=100+1=101,事務(wù)二后更新成功并提交,count=100+1=101,由于事務(wù)二 count 還是從 100 開始增加,事務(wù)一的更新就這樣丟失了。

  3. 虛讀(幻讀)(Phantom Read)
      幻讀是事務(wù)非獨立執(zhí)行時發(fā)生的一種現(xiàn)象。例如事務(wù) T1 對一個表中所有的行的某個數(shù)據(jù)項做了從 “1” 修改為 “2” 的操作,這時事務(wù) T2 又對這個表中插入了一行數(shù)據(jù)項,而這個數(shù)據(jù)項的數(shù)值還是為 “1” 并且提交給數(shù)據(jù)庫。而操作事務(wù) T1 的用戶如果再查看剛剛修改的數(shù)據(jù),會發(fā)現(xiàn)還有一行沒有修改,其實這行是從事務(wù) T2 中添加的,就好像產(chǎn)生幻覺一樣,這就是發(fā)生了幻讀。
      幻讀和不可重復(fù)讀都是讀取了另一條已經(jīng)提交的事務(wù),所不同的是不可重復(fù)讀查詢的都是同一個數(shù)據(jù)項,而幻讀針對的是一批數(shù)據(jù)整體(比如數(shù)據(jù)的個數(shù))。

現(xiàn)在來看看 MySQL 數(shù)據(jù)庫為我們提供的四種隔離級別以及可避免的問題

隔離級別 第一類丟失更新 臟讀 不可重復(fù)讀 第二類丟失更新 幻讀
Serializable
(串行化)
Repeatable read
(可重復(fù)讀)
×
Read committed
(讀已提交)
× × ×
Read uncommitted
(讀未提交)
× × × × ×

在 MySQL 數(shù)據(jù)庫中默認的隔離級別為 Repeatable read(可重復(fù)讀)。

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

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

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