mysql-Innodb事務隔離級別-repeatable read詳解(轉)

1、事務隔離級別html

ANSI/ISO SQL標準定義了4中事務隔離級別:未提交讀(read uncommitted),提交讀(read committed),重複讀(repeatable read),串行讀(serializable)。mysql

對於不一樣的事務,採用不一樣的隔離級別分別有不一樣的結果。不一樣的隔離級別有不一樣的現象。主要有下面3種如今:sql

一、髒讀(dirty read):一個事務能夠讀取另外一個還沒有提交事務的修改數據。數據庫

二、非重複讀(nonrepeatable read):在同一個事務中,同一個查詢在T1時間讀取某一行,在T2時間從新讀取這一行時候,這一行的數據已經發生修改,可能被更新了(update),也可能被刪除了(delete)。session

三、幻像讀(phantom read):在同一事務中,同一查詢屢次進行時候,因爲其餘插入操做(insert)的事務提交,致使每次返回不一樣的結果集。併發

不一樣的隔離級別有不一樣的現象,並有不一樣的鎖定/併發機制,隔離級別越高,數據庫的併發性就越差,4種事務隔離級別分別表現的現象以下表:測試

隔離級別 髒讀 非重複讀 幻像讀
read uncommitted 容許 容許 容許
read committed   容許 容許
repeatable read     容許
serializable      

2、數據庫中的默認事務隔離級別spa

在Oracle中默認的事務隔離級別是提交讀(read committed)。orm

對於MySQL的Innodb的默認事務隔離級別是重複讀(repeatable read。能夠經過下面的命令查看:htm

mysql> SELECT @@GLOBAL.tx_isolation, @@tx_isolation;

+———————–+—————–+

| @@GLOBAL.tx_isolation | @@tx_isolation  |

+———————–+—————–+

| REPEATABLE-READ | REPEATABLE-READ |

+———————–+—————–+

1 row in set (0.00 sec)

下面進行一下測試:

 

Time Session 1 Session 2
T1 set autocommit=0; set autocommit=0;
T2 mysql> select * from tmp_test;

 

+——+———+ | id   | version | +——+———+ |    1 |       1 | +——+———+

1 row in set (0.00 sec)

 
T3   mysql> update tmp_test set version=2 where id=1;

 

Query OK, 1 row affected (0.02 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from tmp_test;

+——+———+ | id   | version | +——+———+ |    1 |       2 | +——+———+

1 row in set (0.00 sec)

T4 mysql> select * from tmp_test;

 

+——+———+ | id   | version | +——+———+ |    1 |       1 | +——+———+

1 row in set (0.00 sec)

【說明】 Session 2未提交,看到數據不變,無髒讀。

 
T5   commit;
T6 mysql> select * from tmp_test;

 

+——+———+ | id   | version | +——+———+ |    1 |       1 | +——+———+

1 row in set (0.00 sec)

【說明】 Session 2已經提交,仍是看到數據不變,便可以重複讀。

 
T7 commit;  
T8 mysql> select * from tmp_test;

 

+——+———+ | id   | version | +——+———+ |    1 |       2 | +——+———+

1 row in set (0.00 sec)

【說明】 提交事務,看到最新數據。

 
T9   mysql> insert into tmp_test values(2,1);

 

Query OK, 1 row affected (0.00 sec)

mysql> select * from tmp_test;

+——+———+ | id   | version | +——+———+ |    1 |       2 | |    2 |       1 | +——+———+

2 rows in set (0.00 sec)

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

T10 mysql> select * from tmp_test;

 

+——+———+ | id   | version | +——+———+ |    1 |       2 | +——+———+

1 row in set (0.00 sec)

【說明】 Session 2的insert事務已經提交,看到的數據和T8的時候同樣,即未發生幻象讀。

 
T11 mysql> commit;

 

Query OK, 0 rows affected (0.00 sec)

mysql> select * from tmp_test;

+——+———+ | id   | version | +——+———+ |    1 |       2 | |    2 |       1 | +——+———+

2 rows in set (0.00 sec)

【說明】 事務提交,看到最新數據。

 

上面的結果能夠看到Innodb的重複讀(repeatable read)不容許髒讀,不容許非重複讀(便可以重複讀,Innodb使用多版本一致性讀來實現)和不容許幻象讀(這點和ANSI/ISO SQL標準定義的有所區別)。

另外,一樣的測試:

一、當session 2進行truncate表的時候,這個時候session 1再次查詢就看不到數據。

二、當session 2進行alter表的時候,這個時候session 1再次查詢就看不到數據。

 

形成以上的緣由是由於 mysql的持續非鎖定讀,在repeatable read級別下,讀採用的是持續非鎖定讀。相關介紹見下面:

持續讀意味着InnoDB使用它的多版本化來給一個查詢展現某個時間點處數據庫的快照。查詢看到在那個時間點以前被提交的那些確切事務作的更改,而且沒有其後的事務或未提交事務作的改變。這個規則的例外是,查詢看到發佈該查詢的事務自己所作的改變。

若是你運行在默認的REPEATABLE READ隔離級別,則在同一事務內的全部持續讀讀取由該事務中第一個這樣的讀所確立的快照。你能夠經過提交當前事務並在發佈新查詢的事務以後,爲你的查詢得到一個更新鮮的快照。

持續讀是默認模式,在其中InnoDBzai在READ COMMITTED和REPEATABLE READ隔離級別處理SELECT語句。持續讀不在任何它訪問的表上設置鎖定,所以,其它用戶可自由地在持續讀在一個表上執行的同一時間修改這些表。

注意,持續讀不在DROP TABLE和ALTER TABLE上做用。持續讀不在DROP TABLE上做用,由於MySQL不能使用已經被移除的表,而且InnoDB 破壞了該表。持續讀不在ALTER TABLE上做用,由於它在某事務內執行,該事務建立一個新表,而且從舊錶往新表中插入行。如今,當你從新發出持續讀之時,它不能在新表中看見任何行,由於它們被插入到一個在持續讀讀取的快照中不可見的事務 裏。

相關文章
相關標籤/搜索