MySQL REPEATABLE-READ && 幻讀mysql
關於mysql命令行中事務控制的語句見該文章sql
http://my.oschina.net/xinxingegeya/blog/296459session
關於MVCC多版本控制spa
http://my.oschina.net/xinxingegeya/blog/208821.net
表結構命令行
create table t1( a int primary key, b int not null )
這裏打開兩個mysql的命令行窗口,窗口A,即session1,窗口B,即session2。版本控制
session1code
mysql> begin ; Query OK, 0 rows affected (0.00 sec) mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | +----+------+ 4 rows in set (0.00 sec)
以上sql只是顯示的開啓了事務,執行了sql查詢。下面看session2的操做。blog
要注意這裏的select操做是通常的快照讀。根據MVCC多版本控制規則讀取的數據行。事務
session2
mysql> begin ; Query OK, 0 rows affected (0.00 sec) mysql> insert into t1 values (55, 3000); Query OK, 1 row affected (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.03 sec) mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | | 55 | 3000 | +----+------+ 5 rows in set (0.00 sec)
session2插入了一條數據,並顯式的提交了事務。
session1
此時返回session1進行如下操做
mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | +----+------+ 4 rows in set (0.00 sec)
此時,雖然在session2中插入了一條數據,而且提交了事務,但在session1中的查詢和session1的上次查詢仍是同一個結果,這就是重複讀。(也能夠說是根據MVCC規則讀取的數據行)。若是是在"READ-COMMITTED"級別下是能夠讀到a=55這條記錄的(由於session2在剛纔已經提交了事務)。
session1
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t1 where a = 56; +----+------+ | a | b | +----+------+ | 56 | 7000 | +----+------+ 1 row in set (0.00 sec)
session1,開啓了一個事務,查詢a = 56 的記錄。
session2
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> update t1 set b = 8000 where a = 56; Query OK, 1 row affected (0.00 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from t1 where a = 56; +----+------+ | a | b | +----+------+ | 56 | 8000 | +----+------+ 1 row in set (0.00 sec) mysql> commit -> ; Query OK, 0 rows affected (0.04 sec)
session2開啓了事務,更新a = 56 的記錄,同時查詢a = 56 的記錄,能夠看到在同一事務內重複讀的效果。
session1
mysql> select * from t1 where a = 56; +----+------+ | a | b | +----+------+ | 56 | 7000 | +----+------+ 1 row in set (0.00 sec)
和上次查詢結果一致,驗證了重複讀。仍是要注意這裏的select操做只是通常的快照讀。其實無論session2 作什麼操做,這裏的快照讀都是重複讀的。
此時,若是session1提交該事務,從新開啓事務,查詢能查到session2中修改的結果
mysql> commit; Query OK, 0 rows affected (0.00 sec) mysql> select * from t1 where a = 56; +----+------+ | a | b | +----+------+ | 56 | 8000 | +----+------+ 1 row in set (0.00 sec)
注:以上的重複讀,雖然在當前事務中真的是重複讀的現象,但到底來講是經過MVCC多版本控制實現的可重複讀。
session1
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | | 55 | 4000 | | 56 | 8000 | +----+------+ 6 rows in set (0.00 sec)
開啓事務,select操做爲快照讀。
session2
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | | 55 | 4000 | | 56 | 8000 | +----+------+ 6 rows in set (0.00 sec) mysql> insert into t1 values (57, 1000); Query OK, 1 row affected (0.00 sec) mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | | 55 | 4000 | | 56 | 8000 | | 57 | 1000 | +----+------+ 7 rows in set (0.00 sec) mysql> commit; Query OK, 0 rows affected (0.11 sec)
在session2 中作了一系列的操做,插入insert,這裏實際上是當前讀(寫入)。而後提交事務。
session1
mysql> update t1 set b = b+1000; Query OK, 7 rows affected (0.00 sec) Rows matched: 7 Changed: 7 Warnings: 0 mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 4000 | | 52 | 4000 | | 53 | 4000 | | 54 | 4000 | | 55 | 5000 | | 56 | 9000 | | 57 | 2000 | +----+------+ 7 rows in set (0.00 sec)
session1作更新操做,這裏更新成功。若是session2 插入記錄後,沒有提交事務,這裏更新是要阻塞的,由於session2 插入記錄持有那條記錄的X鎖。
session1整個會話的sql
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | | 55 | 4000 | | 56 | 8000 | +----+------+ 6 rows in set (0.00 sec) mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 3000 | | 52 | 3000 | | 53 | 3000 | | 54 | 3000 | | 55 | 4000 | | 56 | 8000 | +----+------+ 6 rows in set (0.00 sec) mysql> update t1 set b = b+1000; Query OK, 7 rows affected (0.00 sec) Rows matched: 7 Changed: 7 Warnings: 0 mysql> select * from t1; +----+------+ | a | b | +----+------+ | 51 | 4000 | | 52 | 4000 | | 53 | 4000 | | 54 | 4000 | | 55 | 5000 | | 56 | 9000 | | 57 | 2000 | +----+------+ 7 rows in set (0.00 sec) mysql>
能夠看到多出了一行,這算是幻讀嗎?其實不是。這是根據MVCC的select規則讀出來的數據
請詳見http://my.oschina.net/xinxingegeya/blog/505675
REPEATABLE READ:在mysql中,不會出現幻讀。mysql的實現和標準定義的RR隔離級別有差異。
==========END==========