ACID模型
MYSQL傳統(tǒng)關(guān)系數(shù)據(jù)庫的ACID模型有以下特性
- Atomicity原子性:一個事務(wù)中所有操作都必須全部完成,要么全部不完成。
- Consistency一致性. 在事務(wù)開始或結(jié)束時,數(shù)據(jù)庫應(yīng)該在一致狀態(tài)。
- Isolation隔離性. 事務(wù)將假定只有它自己在操作數(shù)據(jù)庫,彼此不知曉。
- Durability持久性.一旦事務(wù)完成,就不能返回。
MYSQL-ACID模型的實現(xiàn)原理如下
- 事務(wù)的原子性是通過 undo log 來實現(xiàn)的
- 事務(wù)的持久性性是通過 redo log 來實現(xiàn)的
- 事務(wù)的隔離性是通過 (讀寫鎖+MVCC)來實現(xiàn)的
- 而事務(wù)的終極大 boss 一致性是通過原子性,持久性,隔離性來實現(xiàn)的!?。?/li>
下面就逐一介紹其實現(xiàn)原理
原子性(Atomicity)原理
一個事務(wù)必須被視為不可分割的最小工作單位,一個事務(wù)中的所有操作要么全部成功提交,要么全部失敗回滾,對于一個事務(wù)來說不可能只執(zhí)行其中的部分操作,這就是事務(wù)的原子性。
數(shù)據(jù)庫是通過回滾操作來實現(xiàn)原子性的。 所謂回滾操作就是當發(fā)生錯誤異?;蛘唢@式的執(zhí)行rollback語句時需要把數(shù)據(jù)還原到原先的模樣,所以這時候就需要用到undo log來進行回滾。undo log 就是用于記錄更新或新增操作之前的數(shù)據(jù)狀態(tài),當出現(xiàn)需要回滾的情況時,將原數(shù)據(jù)刷回到數(shù)據(jù)庫中,從而保證操作的原子性,具體實現(xiàn)方式如下:
上面從銀行賬戶轉(zhuǎn)賬到理財賬戶的操作步驟如下
- 1.事務(wù)開始
- 2.查詢數(shù)據(jù)
- 3.進行update操作,balance=balance-400;
- 4.記錄zhangsan(1000)到undo log 日志中,回滾時需要將數(shù)據(jù)更新回來
- 5.進行update操作,amount=amount+400;
- 6.記錄amount(0)到undo log日志中,回滾的時候需要將數(shù)據(jù)刷新回來
- 7.事務(wù)提交/回滾
持久性(Durability)原理
事務(wù)一旦提交,其所作做的修改會永久保存到數(shù)據(jù)庫中,此時即使系統(tǒng)崩潰修改的數(shù)據(jù)也不會丟失。
MySQL的數(shù)據(jù)存儲,表數(shù)據(jù)是存放在磁盤上的,因此想要存取的時候都要經(jīng)歷磁盤IO,然而即使是使用SSD磁盤IO也是非常消耗性能的。 為此,為了提升性能InnoDB提供了緩沖池(Buffer Pool),Buffer Pool中包含了磁盤數(shù)據(jù)頁的映射,可以當做緩存來使用:
- 讀數(shù)據(jù):會首先從緩沖池中讀取,如果緩沖池中沒有,則從磁盤讀取在放入緩沖池;
- 寫數(shù)據(jù):會首先寫入緩沖池,緩沖池中的數(shù)據(jù)會定期同步到磁盤中;
上面這種緩沖池的措施雖然在性能方面帶來了質(zhì)的飛躍,但是它也帶來了新的問題,當MySQL系統(tǒng)宕機,斷電的時候可能會丟數(shù)據(jù)!因為我們的數(shù)據(jù)已經(jīng)提交了,但此時是在緩沖池里頭,還沒來得及在磁盤持久化,所以我們急需一種機制需要存一下已提交事務(wù)的數(shù)據(jù),為恢復(fù)數(shù)據(jù)使用。redo log就派上用場了。
redo log來記錄已成功提交事務(wù)的修改信息,并且會把redo log持久化到磁盤,系統(tǒng)重啟之后在讀取redo log恢復(fù)最新數(shù)據(jù)。
隔離性(Isolation)原理
Mysql 隔離級別有以下四種(級別由低到高):
- READ UNCOMMITED (讀未提交)
- READ COMMITED (讀提交)
- REPEATABLE READ (可重復(fù)讀)
- SERIALIZABLE (串行化)
隔離性是要管理多個并發(fā)讀寫請求的訪問順序。 這種順序包括串行或者是并行,從隔離性的實現(xiàn)可以看出這是一場數(shù)據(jù)的可靠性與性能之間的權(quán)衡,可靠性性高的,并發(fā)性能低(比如 Serializable),可靠性低的,并發(fā)性能高(比如 Read Uncommited),不同的隔離級別會有不同的問題
| - | 臟讀 | 不可重復(fù)讀 | 幻讀 |
|---|---|---|---|
| 讀未提交 | √ | √ | √ |
| 讀已提交 | × | √ | √ |
| 不可重復(fù)讀 | × | × | √ |
| 串行化 | × | × | × |
- 臟讀:事務(wù)中讀取到了其他事務(wù)沒有提交的數(shù)據(jù),主要是讀寫完全沒有加鎖造成的
- 不可重復(fù)讀:事務(wù)中多次讀取結(jié)果不一致,因為多次讀取中間,其他事務(wù)修改并提交了數(shù)據(jù)(主要原因是修改)
- 幻讀:事務(wù)中多次范圍讀取結(jié)果不一致,因為多次讀取中間,其他事務(wù)修改并提交了數(shù)據(jù)(主要原因是新增/刪除)
讀未提交(READ UNCOMMITED)
:在該隔離級別下,事務(wù)中的修改即使還沒提交,對其他事務(wù)是可見的。其他事務(wù)可以讀取其未提交的數(shù)據(jù),造成臟讀。
:因為讀不會加任何鎖,所以寫操作在讀的過程中修改數(shù)據(jù),所以會造成臟讀。好處是可以提升并發(fā)處理性能,能做到讀寫并行。
讀提交(READ COMMITTED)
:在該隔離級別下,事務(wù)中的修改如果還沒提交,對其他事務(wù)是不可見的。不會造成臟讀,但是多次讀取會造成數(shù)據(jù)不一致的情況,會有不可重復(fù)度的問題,例如:一個事務(wù)中兩次讀取,在這中間他事務(wù)進行了一個更新并提交,那么兩次讀取的內(nèi)容會不一樣。
:InnoDB在該隔離級別下讀取數(shù)據(jù)不加鎖而是使用了MVCC機制(詳情如下)
可重復(fù)讀 (REPEATABLE READ)
Mysql隔離級別。在一個事務(wù)內(nèi)的多次讀取的結(jié)果是一樣的。這種級別下可以避免,臟讀,不可重復(fù)讀等查詢問題,Innodb可以解決還可以解決幻讀問題。Mysql 有兩種機制可以達到這種隔離級別的效果,分別是采用讀寫鎖和MVCC機制來實現(xiàn)。
- 采用MVCC的實現(xiàn):使用
的方式支持并行讀寫并行內(nèi)部使用MVCC原理(后面介紹)
- 采用鎖的實現(xiàn):使用
對于SELECT... FOR UPDATE ,SELECT ... LOCK IN SHARE MODE 等情況使用的是加鎖解決機制(記錄鎖,間隙鎖等實現(xiàn))
串行化(SERIALIZABLE)
- 該隔離級別理解起來最簡單,實現(xiàn)也最單。在隔離級別下除了不會造成數(shù)據(jù)不一致問題,沒其他優(yōu)點。
MVCC (多版本控制)
MVCC (MultiVersion Concurrency Control) 叫做多版本并發(fā)控制,主要是針對事務(wù)中并行普通讀取的優(yōu)化。
InnoDB在實現(xiàn)的 MVCC的時候使用一致性視圖來保證RC(讀提交),和RR(可重復(fù)讀)事務(wù)隔離級別的實現(xiàn) ,是事務(wù)開啟時,對整個庫創(chuàng)建快照(read view),是通過每行記錄的后面保存兩個隱藏的列來實現(xiàn)的。這兩個列, 一個保存了行的創(chuàng)建時間,一個保存了行的過期時間, 當然存儲的并不是實際的時間值,而是系統(tǒng)版本號。每當修改數(shù)據(jù)時,版本號加一。當事務(wù)讀取時,如果數(shù)據(jù)的當前版本號大于自己的事務(wù),則查詢的時候拋棄。從而實現(xiàn)不加鎖讀進而做到讀寫并行。MVCC在mysql中的實現(xiàn)依賴的是undo log與read view
- undo log :undo log 中記錄某行數(shù)據(jù)的多個版本的數(shù)據(jù)。
- read view :用來判斷當前版本數(shù)據(jù)的可見性
在不同的隔離級別下,MVCC創(chuàng)建read view歷史版本的時機也是不同的
- 在讀提交隔離級別下:視圖 read-view的創(chuàng)建是在語句執(zhí)行的時候創(chuàng)建的
- 在可重復(fù)讀隔離級別下:視圖 read-view的創(chuàng)建是在事務(wù)啟動的時候創(chuàng)建的
幻讀問題詳解
幻讀在業(yè)務(wù)中存在兩種情況,快照讀,和當前讀,MVCC策略能夠解決快照讀的問題,但是對于當前讀則需要使用間隙鎖。是指讀取數(shù)據(jù)庫中最新版本的數(shù)據(jù),在多個update的時候不能基于快照讀。讀取歷史版本的數(shù)據(jù)進行更新,會導(dǎo)致數(shù)據(jù)不一致問題
- 快照讀:當使用普通select * 進行統(tǒng)計的時候,使用MVCC可以保證幻讀問題
- 當前讀:當使用select for update 或者 select ... lock in share mode 操作的時候,insert,update,delete等操作都會被阻塞。當前讀是通過手動加record lock(記錄鎖)和gap lock(間隙鎖 )來實現(xiàn)的



