【MySQL】淺談一致性讀

楊奇龍發表於2017-09-05
一 前言
   MySQL 在不同的事務隔離級別下提供兩種讀模式 一致性讀(非加鎖)當前讀(加鎖讀)。當前讀比較簡單,本文主要研究一致性讀取。
二 原理概念

官方概念
  1. "A consistent read means that InnoDB uses multi-versioning to present to a query a snapshot of the database at a point in time. The query sees the changes made by transactions that committed before that point of time, and no changes made by later or uncommitted transactions.The exception to this rule is that the query sees the changes made by earlier statements within the same transaction. "
一致性讀是指使用MVCC機制讀取到某個事務已經提交的資料,其實是從undo裡面獲取的資料快照。不過也有特例: 在本事務內如果修改某個表之後的select 可以讀取到該表最新的資料,後面的例子可以驗證。   
三 不同事務隔離級別的一致性讀
3.1 RR模式
從官方文件 "If the transaction isolation level is REPEATABLE READ (the default level), all consistent reads within the same transaction read the snapshot established by the first such read in that transaction."
 在RR模式下,同一個事務內的一致性讀的快照都是基於第一次讀取操作時所建立的。下面我們做測試進行對RR模式下一致性讀進行解讀。
a)RR模式下事務的起始點是以執行的第一條語句為起始點的,而不是以begin作為事務的起始點的。

session 1

session2 

test [RW] 10:01:33 >begin;

Query OK, 0 rows affected (0.00 sec)


test [RW] 10:02:12 >begin;

Query OK, 0 rows affected (0.00 sec)


test [RW] 10:02:22 >select * from ty;

Empty set (0.00 sec)

test [RW] 10:02:36 >insert into ty(a,b) values(1,2);

Query OK, 1 row affected (0.00 sec)

test [RW] 10:02:51 >commit;

Query OK, 0 rows affected (0.00 sec)

test [RW] 10:02:33 >select * from ty;

+----+------+------+

| id | a    | b    |

+----+------+------+

|  1 |    1 |    2 |

+----+------+------+

1 row in set (0.00 sec)




b)RR模式下的一致性讀,是以第一條select語句的執行時間點作為snapshot建立的時間點的,即使是訪問不同的表。

test [RW] 10:35:11 >begin;

Query OK, 0 rows affected (0.00 sec)

test [RW] 10:35:13 >select * from x;

+----+

| id |

+----+

|  1 |

|  2 |

+----+

2 rows in set (0.00 sec)

test [RW] 10:34:32 >begin;

Query OK, 0 rows affected (0.00 sec)


test [RW] 10:34:51 >insert into ty(a,b) values(2,4);

Query OK, 1 row affected (0.00 sec)

test [RW] 10:35:39 >select * from ty;

+----+------+------+

| id | a    | b    |

+----+------+------+

|  1 |    1 |    2 |

+----+------+------+

1 row in set (0.00 sec)




c)RR模式下,在本事務內如果修改某個表之後的對該表的select語句可以讀取到該表最新的資料。

test [RW] 10:42:56 >begin;

Query OK, 0 rows affected (0.00 sec)

test [RW] 10:43:07 >select * from ty;

+----+------+------+

| id | a    | b    |

+----+------+------+

|  1 |    1 |    2 |

|  2 |    2 |    4 |

+----+------+------+

2 rows in set (0.00 sec)

test [RW] 10:35:34 >begin;

Query OK, 0 rows affected (0.00 sec)

test [RW] 10:43:25 >insert into ty(a,b) values(3,5);

Query OK, 1 row affected (0.00 sec)


test [RW] 10:43:38 >select * from ty;

+----+------+------+

| id | a    | b    |

+----+------+------+

|  1 |    1 |    2 |

|  2 |    2 |    4 |

|  3 |    3 |    5 |

+----+------+------+

3 rows in set (0.00 sec)

test [RW] 10:43:14 >update  ty set a = 5 where id=3;

Query OK, 1 row affected (4.23 sec)

Rows matched: 1  Changed: 1  Warnings: 0

test [RW] 10:44:30 >select * from ty;

+----+------+------+

| id | a    | b    |

+----+------+------+

|  1 |    1 |    2 |

|  2 |    2 |    4 |

|  3 |    5 |    5 |

+----+------+------+

3 rows in set (0.00 sec)



d)RR模式下同一個事務內,第一次查詢是當前讀操作則後續查詢可以檢視最新的資料。

test [RW] 11:07:23 >begin;

Query OK, 0 rows affected (0.00 sec)

test [RW] 11:07:26 >update ty set a=5 where id=2;

Query OK, 1 row affected (0.00 sec)

Rows matched: 1  Changed: 1  Warnings: 0

test [RW] 11:07:31 >begin;

Query OK, 0 rows affected (0.00 sec)


test [RW] 11:07:33 >select * from ty where id=2 for update;

+----+------+------+

| id | a    | b    |

+----+------+------+

|  2 |    5 |    4 |

+----+------+------+

1 row in set (10.73 sec)

test [RW] 11:07:36 >insert into ty(a,b) values(6,7);

Query OK, 1 row affected (0.00 sec)

test [RW] 11:07:55 >commit;

Query OK, 0 rows affected (0.00 sec)



test [RW] 11:07:58 >select * from ty;

+----+------+------+

| id | a    | b    |

+----+------+------+

|  1 |    2 |    3 |

|  2 |    5 |    4 |

|  3 |    6 |    7 |  <-- 本事務還未commit,已經可以檢視其他會話最新插入的資料

+----+------+------+

3 rows in set (0.00 sec)

這個例子要特別說明一下,從上面的實驗結果上來看RR事務隔離級別下,一致性快照的建立僅僅和select語句第一次執行有關,不管是不是相關表。而且與其他 DML(insert,update,delete) 語句、for update 語句無關,在事務中第一次執行DML,後面的其他select 查詢會是當前讀即可獲取到最新的資料。
   
3.2 RC模式 
RC 支援在本事務內讀取到最新提交的資料,所以RC 事務隔離級別下的一致性讀取比RR模式下的要簡單很多。每個事務構建自己的快照,不相互干擾,除非其他事務已經提交,有興趣的朋友自己測試吧。
  1. With READ COMMITTED isolation level, each consistent read within a transaction sets and reads its own fresh snapshot.
四 當前讀 
    和一致性讀不太一樣 ,當前讀需要使用select  xx  for update,或者 lock in share mode ,讀取最新的資料並且鎖定被訪問的行,(RC 加行鎖,RR加gap鎖 唯一鍵除外) 不管另外一個事務是否提交,如果另外的事務已經獲取了相關的鎖,則 for update,lock in share mode 語句則繼續等待直到其他事務釋放鎖,並且獲取到最新的資料。
  
五 小結
    從上面的測試來看,RR模式下的一致性快照讀會有比較多的特性(姑且叫做特性吧) 。RC模式本身支援不可重複讀,能夠查詢到最新的其他事務最新提交的資料。基於上面的測試,還是比較推薦業務使用RC模式作為事務隔離級別的。
參考文章
[1] 一致性讀深入研究
[2] 官方文件

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22664653/viewspace-2144551/,如需轉載,請註明出處,否則將追究法律責任。

相關文章