天天看點

資料庫的讀一緻性分析

前言

提起資料庫的事務,我們就會想到ACID特性:

A:Atomicity 原子性    事務中包含的各種操作,要麼一起成功,要麼全部失敗

C:Consistency 一緻性  事務從一個一緻性的狀态轉變成另一個一緻性的狀态 

I:Isolation 隔離性   各個事務之間的可見程度

D:Durability 持久性  資料庫中的資料的改變應該是可以持久存儲的

本篇部落格将以MySQL為例分析資料庫的讀一緻性。想分析清楚一緻性,必先了解隔離級别。

資料庫的隔離級别

在SQL标準中是定義了幾種隔離級别的:

RU:Read Uncommitted(讀取未送出内容)

RC:Read Committed(讀取送出内容)

RR:Repeatable Read(可重讀)

Serializable(可串行化)

Serializable這種隔離級别最高,若幾個事務對同一份資料進行操作(即便是查詢操作),它也針對每一個事務進行排序,嚴格按照排序進行事務的執行,顯然解決了事務可能存在的沖突,但是會導緻大量的逾時以及鎖競争,是以在實際中大多是不會采用此種隔離級别的。

Oracle預設的隔離級别是:RC,并且Oracle隻支援RC和Serializable這2種級别。RC,簡單一句話,就是一個事務中隻能看到另一個事務已經送出的資料的改變。那麼RC會帶來什麼問題呢?在同一事務中,同一條SELECT語句可能會傳回不一樣的結果,即會産生  不可重複讀。

MySQL預設的隔離級别是:RR。在該隔離級别下,可以保證在同一事務中,擷取到的資料一緻。這就是所謂的MySQL的讀一緻性,它的實作基于MVCC,後文中會分析。

RU可以讓所有事務都讀取到其他事務未送出的資料,會帶來 髒讀,同Serializable一樣,在實際中,應用較少。

淺析MySQL MVCC原理

MVCC(MultiVersion Concurrency Control )多版本并發控制,可以簡單的了解成為一個row lock的一個變種,隻是在必要的時候加行鎖。MySQL InnoDB的MVCC簡單來講是通過給表添加兩列隐藏列來是實作的。一列是insert/update的時間,另一列是delete的時間,當然這裡的時間并不是真正的時間,而是指SVN,即System Version Number,系統版本号,就是一個數字。每次開啟一個事務,那麼SVN号遞增。

現在讨論在REPEATABLE READ下的MVCC實作:

SELECT

Innodb查找insert/update SVN小于等于目前事務的SVN的行,如果是小于,說明行之前就已經存在,如果是等于,說明這行是事務本身修改過的。

行的删除時間列要麼為空(說明該行未被删除)要麼删除時間列的SVN大于目前事物的SVN(表示行是在事物開始之後被删除的)。

隻有記錄滿足以上兩條,才會被select語句傳回!

這就是為何MYSQL在RR級别下,一個事務中是肯定讀取不到“之後建立的”别的事務送出的資料,但是在本事務中更新的資料,可以讀取出來的緣故!

INSERT

插入之後以目前事務的SVN号更新建立列

DELETE

删除之後,用目前SVN更新删除列

UPDATE

更新建立列為目前SVN,同時更新删除列為update之前的建立列的SVN值

這樣設計的優點是大部分的讀操作都不用加鎖了,而且是非阻塞的讀取操作,使資料庫操作簡單,性能好,不足之處是增加了存儲開銷,需要額外的維護工作。

還是那句老話,用空間換取時間!

本文轉自zfz_linux_boy 51CTO部落格,原文連結:http://blog.51cto.com/zhangfengzhe/1874662,如需轉載請自行聯系原作者