MySQL INNODB存儲引擎,實現的是基於多版本的併發控制協議——MVCC (Multi-VERSION Concurrency Control)。MVCC最大的好處,相信也是耳熟能詳:讀不加鎖,讀寫不衝突。在讀多寫少的OLTP應用中,讀寫不衝突是很是重要的,極大的增長了系統的併發性能,這也是爲何現階段,幾乎全部的RDBMS,都支持了MVCC。數據庫
在MVCC併發控制中,讀操做能夠分紅兩類:快照讀 (snapshot read)與當前讀 (current read)。快照讀,讀取的是記錄的可見版本 (有多是歷史版本),不用加鎖。當前讀,讀取的是記錄的最新版本,而且當前讀返回的記錄,都會加上鎖,保證其餘事務不會再併發修改這條記錄。併發
在一個支持MVCC併發控制的系統中,哪些讀操做是快照讀?哪些操做又是當前讀呢?以MySQL InnoDB爲例:性能
快照讀:簡單的SELECT操做,屬於快照讀,不加鎖。(固然也有例外,下面會分析)spa
select * from table where ?;blog
當前讀:特殊的讀操做,插入/更新/刪除操做,屬於當前讀,須要加鎖。事務
select * from table where ? lock in share mode;ip
select * from table where ? for update;get
insert into table values (…);table
update table set ? where ?;date
delete from table where ?;
爲何將 插入/更新/刪除 操做,都歸爲當前讀?能夠看看下面這個 更新 操做,在數據庫中的執行流程:
從上圖能夠看出,當UPDATE SQL被髮給MySQL後,MySQL SERVER會根據WHERE條件,讀取第一條知足條件的記錄,而後INNODB引擎會將第一條記錄返回,並加鎖 (current READ)。待MySQL SERVER收到這條加鎖的記錄以後,會再發起一個UPDATE請求,更新這條記錄。一條記錄操做完成,再讀取下一條記錄,直至沒有知足條件的記錄爲止。所以,UPDATE操做內部,就包含了一個當前讀。同理,DELETE操做也同樣。INSERT操做會稍微有些不一樣,簡單來講,就是INSERT操做可能會觸發UNIQUE KEY的衝突檢查,也會進行一個當前讀。
注:根據上圖的交互,針對一條當前讀的SQL語句,INNODB與MySQL SERVER的交互,是一條一條進行的,所以加鎖也是一條一條進行的。先對一條知足條件的記錄加鎖,返回給MySQL SERVER,作一些DML操做;而後在讀取下一條加鎖,直至讀取完畢
傳統RDBMS加鎖的一個原則,就是2PL (二階段鎖):Two-Phase Locking。相對而言,2PL比較容易理解,說的是鎖操做分爲兩個階段:加鎖階段與解鎖階段,而且保證加鎖階段與解鎖階段不相交。下面,仍舊以MySQL爲例,來簡單看看2PL在MySQL中的實現。
從上圖能夠看出,2PL就是將加鎖/解鎖分爲兩個徹底不相交的階段。加鎖階段:只加鎖,不放鎖。解鎖階段:只放鎖,不加鎖。