資料庫ACID、隔離級別與MVCC
http://www.cnblogs.com/lidabnu/p/4495785.html
首先需要明確事務的概念:一組原子性的SQL查詢,如果資料庫引擎能夠成功的對資料庫應用該組查詢的全部語句,那麼就執行該組語句,否則所有語句都不執行。
事務有ACID四個特性,即:
原子性:一個事務是一個不可分割的最小工作單元,其操作要麼全部成功,要麼全部失敗;
一致性:資料庫總是從一個一致性狀態轉換為另一個一致性狀態。所謂一致性狀態,就是資料庫的所有完整性約束(尤其注意使用者定義約束)都被遵守,以銀行轉賬為例,“轉賬操作必然導致一個賬戶減少金額,另一個賬戶增加金額,且這兩個賬戶總金額之和不變”就是一個完整性約束。
永續性:一旦事務提交,則其所作的修改就會永久儲存到資料庫中
隔離性:隔離性用於定義事務之間的相互隔離程度,存在四個隔離級別。
首先需要解釋一下幾個跟隔離性相關的概念定義:
(1)髒讀:指事務讀到髒資料,所謂髒資料,指的是不正確的資料,例如事務執行過程中修改了某記錄,然後回滾,如果其他事務讀到了該記錄的中間修改值,則為髒讀。
(2)不可重複讀:事務在執行過程中,多次對同一個已經存在的記錄進行讀取,各次讀取的值不同。讀提交隔離級別存在不可重複讀的問題,事務1、2併發執行,事務2首先讀取記錄1,然後事務1修改記錄1並提交,事務2繼續讀取記錄1,則事務2兩次讀取到的值不同。
(3)幻讀:幻讀是指使用某個條件讀取一批記錄時,可能讀到的記錄數不同。幻讀與髒讀、不可重複讀的區別在於,髒讀、不可重複讀都是針對某個確定的已經存在的記錄出現的值不要求(讀到髒資料或多次讀的值不同),而幻讀則是多次使用同一個條件查詢一批記錄,多次讀到的記錄數不同,也就是說,髒讀、不可重複讀是由於多個事務並行執行update引起的,而幻讀則是由於多個事務並行執行insert引起的(併發delete引起的問題看起來算哪個都行……)。
四個隔離級別為:
(1)Read Uncommited:讀未提交,其含義為多個併發事務,任何一個事務可以讀到其他事務尚未提交的修改:
存在髒讀、不可重複讀、幻讀可能性。
(2)Read Commited:讀已提交,含義為多個併發事務,任何一個事務只可以讀到其他事務已經提交的修改:
解決髒讀,存在不可重複讀、幻讀可能性。
(3)Repeatable Read:可重複讀,含義為多個事務併發執行時,任何一個事務反覆讀取已存在的記錄,每次讀到的值都是相同的
解決髒讀、不可重複讀,存在幻讀可能性。
(4)Serializable:序列化,含義為所有事務序列執行,因此不存在事務併發執行的情況。
解決髒讀、不可重複讀、幻讀。
多版本併發控制MVCC
上述四個隔離級別中,讀未提交隔離性最差,且相對於讀已提交,效能並沒有多少提升,幾乎不會使用;序列化隔離性最好,可是效能太差,也幾乎不會使用。一般資料庫的預設隔離級別要麼是讀已提交,要麼是可重複讀(例如MySQL的InnoDB引擎),要麼是讀已提交(例如Oracle )。
如果使用行級讀鎖、寫鎖來實現讀已提交或可重複讀,應當是以下的步驟:
1、事務1會修改行1,則會在行1加上寫鎖,開始事務;
2、事務2為純讀取操作,需要讀取行1,試圖在行1上加上讀鎖,由於事務1已加寫鎖,因此事務2等待直到事務1完成。
3、如果事務2先開始,則事務1也需要等到事務2完成並釋放讀鎖後才可以開始執行。
也即使說,對某行的寫操作會阻塞所有對該行的讀取操作,對某行的讀操作會阻塞所有對該行的寫操作,在系統存在讀、寫併發時,不論系統IO能力有多高,會受限於鎖而導致效能低下。
MVCC用於解決這個問題來提高系統效能,MVCC並沒有統一的標準,各個資料庫實現均採用不同方式來實現MVCC,InnoDB的實現方式如下:
準備工作:
(1)對每行記錄增加行標誌和刪除標誌兩個欄位;
(2)維護一個全域性的系統版本號,每開始一個事務(注意select也是事務,讀事務),將該系統版本號加1並作為事務的版本號
插入記錄的行標誌設定為本事務版本號,刪除標誌為空;
刪除記錄的刪除標誌設定為本事務版本號;
修改的處理過程:將原記錄的刪除版本號修改為本事務版本號;新插入一條記錄,包含原記錄資料及本次修改,行記錄標誌設定為本事務版本號,刪除標誌為空;
讀取的處理過程:
僅讀取同時滿足以下條件的記錄行:
(1)行標誌小於或等於本事務版本號(等於用於保證能夠讀取到本事務內提交的增加);
(2)刪除標誌為空或者大於本事務版本號(不包括等於以保證不會讀取到本事務刪除的記錄);
相當於在讀事務開始的時刻點,建立了一個系統的快照,該事務讀取的所有資料,均是從快照中讀取的,因此滿足可重複讀的條件,並且可解決幻讀的問題,並且也不會讀到產生“同樣查詢條件,事務中第一次讀到的記錄數大於第二次讀到的記錄數的問題“(由併發刪除引起)
從上可知,使用MVCC後,大部分讀都不再需要加讀鎖,因此讀不再阻塞寫,寫也不再阻塞讀。讀操作只再受限於系統IO能力。
昨天去去哪兒網面試,老周和老趙問了很多問題,大多關於細節,其中就包括事務隔離級別和MVCC,由於準備不夠充分,所以今天特地進行驗證。
其中隔離級別中,比較讓人難以理解的是repeatable read可重複讀,和serializable序列讀,下面依次進行試驗,檢視彼此區別。
serializable隔離級別:
session 1 | session 2 |
mysql> show variables like ‘%iso%‘; +---------------+--------------+ | Variable_name | Value | +---------------+--------------+ | tx_isolation | SERIALIZABLE | +---------------+--------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---+ | i | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | +---+ 5 rows in set (0.00 sec) |
mysql> show variables like ‘%iso%‘; +---------------+--------------+ | Variable_name | Value | +---------------+--------------+ | tx_isolation | SERIALIZABLE | +---------------+--------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---+ | i | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | +---+ 5 rows in set (0.00 sec) |
mysql> insert into t values (6); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
|
mysql> insert into t values (10); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
|
上面現象說明:當隔離級別為serializable的時候,不相容MVCC,嚴格遵循鎖機制,當session1 和session2都進行全表查詢時,兩個會話都會全表加讀鎖,由於讀鎖只和讀鎖相相容,所以此時任何一個會話都無法修改、插入資料,會進入所等待。 |
repeatable read隔離級別:
session 1 | session 2 |
mysql> show variables like ‘%iso%‘; +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | tx_isolation | REPEATABLE-READ | +---------------+-----------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---+ | i | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | +---+ 5 rows in set (0.00 sec) |
mysql> show variables like ‘%iso%‘; +---------------+-----------------+ | Variable_name | Value | +---------------+-----------------+ | tx_isolation | REPEATABLE-READ | +---------------+-----------------+ 1 row in set (0.00 sec) mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +---+ | i | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | +---+ 5 rows in set (0.00 sec) |
mysql> insert into t values (6); Query OK, 1 row affected (0.00 sec) |
|
mysql> select * from t; +---+ | i | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | | 6 | +---+ 6 rows in set (0.00 sec) |
mysql> select * from t; +---+ | i | +---+ | 1 | | 2 | | 3 | | 4 | | 5 | +---+ 5 rows in set (0.00 sec) |
mysql> insert into t values (6); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction |
|
上面現象說明:當隔離級別為repeatable read時,相容使用MVCC(使用undo),此時兩個事物讀取資料到各自的undo中,事物之間獨立,但是不同事務對於同一行資料的修改會根據順序加上排他鎖。其中上面session 2最後插入一條資料,是因為session 1已經存在並將該行資料鎖定,同時此刻出現在repeatable read隔離級別所特有的幻讀現象(本會話內並沒有該資料,卻依然無法插入)。
|
總結:
MVCC:多版本控制,多個未提交事務所看到的資料都是自己的,彼此不同,在客戶端總體看來彷彿多個版本個資料庫。
MVCC只和隔離級別read-committed和repeatable-read相相容,MACC對於不同事物的同一行的讀寫之間是不加鎖的,對於不同事務的同一行的寫寫加鎖。
MVCC和read-uncommitted和serializable不相容,其中serializable完是由鎖來控制,所有事務均符合鎖特徵。
以下內容摘自:http://www.blogjava.net/neverend/archive/2012/04/05/373357.html
在事務隔離級別設定為repeatable read的情況下,一般的select語句採取的是一致性非阻塞讀的方式。
一致性是指在事務的範圍內讀取的資料是可重現的,不會出現不可重複讀的情況。非阻塞是指這種讀取資料的模式不會對資料上任何一種鎖,其它操作全都不會被阻塞。
在這種模式下,事務執行讀取語句後,相關的資料會有一套副本出現,並會為這個資料副本附加一個時間戳,其它事務在這個時間戳之後執行的寫操作都不會反映到這個副本中,這種機制被稱之為多版本併發控制。
如果用select …… lock in share mode,則不是一致性非阻塞讀,該語句會等待其它事務的寫語句提交或回滾之後再讀取資料;如果事務隔離級別設定為read committed,也不是一致性非阻塞讀,該語句會讀取其它事務提交的資料。
相關文章
- 事務ACID特性與隔離級別
- 事務的隔離級別與MVCCMVC
- 資料庫隔離級別資料庫
- 資料庫事務與隔離級別資料庫
- 還原面試現場-ACID與隔離級別面試
- 資料庫事務 ACID屬性、資料庫併發問題和四種隔離級別資料庫
- Mysql資料庫的隔離級別MySql資料庫
- MySQL事務隔離級別和MVCCMySqlMVC
- MySQL之事務隔離級別和MVCCMySqlMVC
- 資料庫事務與事務的隔離級別資料庫
- 資料庫的四種隔離級別資料庫
- 【進階之路】詳解資料庫事物與隔離級別資料庫
- 聊聊資料庫的事務隔離級別資料庫
- golang saas框架,資料庫級別隔離、讀寫分離Golang框架資料庫
- 論 MySQL 之事務隔離級別 | 資料庫篇MySql資料庫
- MySQL資料庫中的四種隔離級別MySql資料庫
- MySQL資料庫引擎、事務隔離級別、鎖MySql資料庫
- [資料庫]事務的4種隔離級別資料庫
- 資料庫系列:事務的4種隔離級別資料庫
- [轉帖]資料庫的快照隔離級別(Snapshot Isolation)資料庫
- 資料庫之事務、隔離級別和併發問題資料庫
- PostgreSQL DBA(23) - MVCC#3(事務快照和隔離級別)SQLMVCC#
- 資料庫隔離資料庫
- 成為MySQL DBA後,再看ORACLE資料庫(十、事務與隔離級別)MySqlOracle資料庫
- KES資料庫實踐指南:探索KES資料庫的事務隔離級別資料庫
- SQL Server 2017 AlwaysOn輔助副本資料庫的隔離級別SQLServer資料庫
- 資料庫事務的隔離級別及四大特性資料庫
- 資料庫事務的四大特性和隔離級別資料庫
- Java中JDBC進階教程之資料庫的隔離級別!JavaJDBC資料庫
- oracle資料庫事務不同事務隔離級別與v$transaction flag列思考Oracle資料庫
- ACID之I:事務隔離
- 資料庫學習筆記:事務的特性和隔離級別資料庫筆記
- 【每日鮮蘑】資料庫隔離級別、髒讀、幻讀、鎖等資料庫
- 帶你真正理解MySQL資料庫的四種隔離級別!MySql資料庫
- Mysql鎖與事務隔離級別MySql
- 資料庫事務隔離級別– 髒讀、幻讀、不可重複讀資料庫
- MySQL資料庫事務各隔離級別加鎖情況--read uncommittMySql資料庫MIT
- MySQL資料庫事務各隔離級別加鎖情況--Repeatable ReaMySql資料庫
- MySQL的隔離級別MySql