Mysql可重複讀(1) —— 快照何時建立

有讚美業商家經營組技術部落格發表於2019-01-30

原文:zhuanlan.zhihu.com/p/55819387
作者:柳樹

以前,對可重複讀的理解,就是別的事務的提交,對當前事務的查詢結果,不會產生影響;

後來,知道事務在一開始的時候,會生成一個快照;

不過這樣的對可重複讀的理解,依然膚淺。

在我看來,要想真正弄懂可重複讀,至少要把以下幾個名詞,能夠串起來,解釋清楚:

從這一講開始,我就試著用各種例子,把這些知識串起來,給大家講清楚到底什麼是Repeatable Read.

先從簡單的開始,我們說的“快照”,是什麼時候開始建立的?

有同學說,快照在begin的時候就建立了。

是嗎?

我們建一張極簡的表:

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;
複製程式碼

插入兩條資料:

insert into t values(1,1),(2,2);
複製程式碼

然後按照下面表格的順序,在兩個會話視窗執行如下sql語句:

Mysql可重複讀(1) —— 快照何時建立

你可以像我這樣,開啟兩個命令列視窗,分別執行:

Mysql可重複讀(1) —— 快照何時建立

如果Mysql真的是在begin的時候,就建立了快照,那麼session A執行select語句時,查詢到的c應該是1,但是,實際查詢到的,卻是3,說明begin後,快照並沒有立刻生成。

於是我們試著把select語句放到session B的update語句之前:

Mysql可重複讀(1) —— 快照何時建立

這次你會發現,session A在執行第二天select語句時,查詢到的c還是1,說明快照已經在執行第一條select語句時生成了,session B的update對session A不產生影響。

那麼是不是就可以說,快照會在執行那些操作mysql資料庫的sql語句時生成呢?

並不是,只有“快照讀”的sql語句,才會生成快照,比如不加鎖的select語句

而“當前讀”的sql語句,是不會生成快照的,比如update,select ... for update, select .. lock in share mode等;

所以下面這個例子,session A在select時看到的還會是被session B修改的資料,因為在update時並沒有生成快照:

Mysql可重複讀(1) —— 快照何時建立

那你說,我就是想在begin時就生成快照呢?

送你一條sql:

start transaction with consistent snapshot; 
複製程式碼

小結一下:

  • 可重複讀的關鍵,來自於“快照”
  • “快照”並不是在begin後就生成,而是在第一條“快照讀”語句後才生成

那麼問題又來了,“快照”到底是啥?是對當前資料的全量拷貝嗎?難道每開啟一個事務,都要把當前資料庫的資料拷貝一份出來?

下一講,我們們來聊聊可重複讀的實現原理 —— MVCC。

參考

相關文章