MVCC原理(多版本並發控制)
說明
Innodb通過在讀取的時刻建立快照,來保證一個事務中的讀取一致性。
- 在該時刻之前的數據是可以查詢到的
- 在該時刻之后的數據是查詢不到的
- 有一個例外需要注意,如果事務修改了該時刻后面的數據,那么當前事務在查詢時就會讀取到該條數據
演示一
事務A | 事務B |
---|---|
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) |
mysql> select * from user; Empty set (0.00 sec) |
|
mysql> insert into user values(1,'fc'); Query OK, 1 row affected (0.00 sec) |
|
mysql> select * from user; +----+———+ | id | name | +----+———+ | 1 | fc | |
|
mysql> select * from user; Empty set (0.00 sec) |
結論:從第一個查詢操作開始建立快照,該快照應用於整個事務中。
演示二
事務A | 事務B |
---|---|
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) |
mysql> select * from user; Empty set (0.00 sec) |
mysql> select * from user; Empty set (0.00 sec) |
mysql> insert into user values(2,'tt'); Query OK, 1 row affected (0.00 sec) |
|
mysql> select * from user; +----+———+ | id | name | +----+———+ | 1 | fc | +----+------+ 1 row in set (0.00 sec) |
|
mysql> select * from user; Empty set (0.00 sec) |
|
mysql> update user set name = 'xtt' where id = 2; 注意此時事務B的新增語句並沒有提交,這里會一直阻塞,等待事務B的提交 |
|
mysql> commit; | |
Query OK, 1 row affected (29.31 sec) Rows matched: 1 Changed: 1 Warnings: 0 |
|
mysql> select * from user; +----+------+ | id | name | +----+------+ | 2 | xtt | +----+------+ 1 row in set (0.00 sec) |
總結:如果當前事務A修改其他事務B新增未提交的數據,那么會出現阻塞的情況,直到事務B提交事務。那么如果事務B又將該數據刪除了呢,或者事務B是修改了未提交呢?
演示三
事務A | 事務B |
---|---|
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) |
mysql> set autocommit = 0; Query OK, 0 rows affected (0.00 sec) |
mysql> select * from user; +----+———+ | id | name | +----+———+ | 2 | tt | +----+------+ 1 row in set (0.00 sec) |
|
mysql> update user set name = 'niufuren' where id =2; Query OK, 1 row affected (0.00 sec) |
|
mysql> update user set name = 'tt' where id = 2; 注意此時事務B的新增語句並沒有提交,這里會一直阻塞,等待事務B的提交 |
|
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 等待超時 | mysql> commit; Query OK, 0 rows affected (0.00 sec) |
mysql> select * from user; +----+------+ | id | name | +----+------+ | 2 | xtt | +----+------+ 1 row in set (0.00 sec) 這里一致性讀,依然讀的快照 |
總結:如果事務B又將該數據刪除了呢,或者事務B是修改了未提交,事務A再去刪除或者修改該數據時都會阻塞,但是事務A是可以正常讀取的,也就是可重復讀。
快照的創建
-
RR隔離級別下:當事務中第一個需要讀取的操作時創建快照,也可以通過命令在事務開始時就創建快照
-
通用select開啟事務
-
通過start transaction with consistent snapshot;
-
-
RC隔離界別下:事務中每一個一致性讀的操作都會建立自己的新快照
一致性讀不適用與DDL語句
- 當事務A在事務中已經建立了user表的快照是后,其他事務是無法對user表進行DDL的,DDL是直接生效的沒有經過事務提交
- 在RR和RC隔離界別下,一致性讀是不會對行加鎖的
參考:
https://dev.mysql.com/doc/refman/5.6/en/innodb-consistent-read.html