原文:zhuanlan.zhihu.com/p/55819387
作者:柳樹
以前,對可重複讀的理解,就是別的事務的提交,對當前事務的查詢結果,不會產生影響;
後來,知道事務在一開始的時候,會生成一個快照;
不過這樣的對可重複讀的理解,依然膚淺。
在我看來,要想真正弄懂可重複讀,至少要把以下幾個名詞,能夠串起來,解釋清楚:
- 快照讀(consistent nonlocking reads)
- 當前讀(locking reads)
- MVCC
- gap lock
- next-key lock
- 幻讀
從這一講開始,我就試著用各種例子,把這些知識串起來,給大家講清楚到底什麼是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真的是在begin的時候,就建立了快照,那麼session A執行select語句時,查詢到的c應該是1,但是,實際查詢到的,卻是3,說明begin後,快照並沒有立刻生成。
於是我們試著把select語句放到session B的update語句之前:
這次你會發現,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時並沒有生成快照:
那你說,我就是想在begin時就生成快照呢?
送你一條sql:
start transaction with consistent snapshot;
複製程式碼
小結一下:
- 可重複讀的關鍵,來自於“快照”
- “快照”並不是在begin後就生成,而是在第一條“快照讀”語句後才生成
那麼問題又來了,“快照”到底是啥?是對當前資料的全量拷貝嗎?難道每開啟一個事務,都要把當前資料庫的資料拷貝一份出來?
下一講,我們們來聊聊可重複讀的實現原理 —— MVCC。
參考
- 《Mysql實戰45講》丁奇
- Innodb Transaction Isolation Levels