併發即指在同一時刻,多個操做並行執行。MySQL對併發的處理主要應用了兩種機制——是「鎖」和「多版本控制」。數據庫
鎖
鎖分爲讀鎖和寫鎖兩種,也稱做共享鎖和排他鎖。
由於多個讀操做同時進行是不會破壞數據的,因此讀鎖是共享的,多個讀操做能夠同時進行,互不干擾。
爲了防止多個寫操做共同執行破壞數據,寫鎖是排他的,一個寫鎖會阻塞其它的寫鎖和讀鎖,進而保證同一資源在任什麼時候刻只有一個寫操做在執行,並防止其它用戶讀取正在寫入的該資源。
在鎖粒度方面,MySQL包括表鎖和行鎖兩種類型。鎖的粒度越小,越有利於對數據庫操做的併發執行。可是管理鎖消耗的資源也會更多。若是系統花費大量的時間來管理鎖,而不是存儲數據,那麼系統的性能也會受到影響。
表鎖會鎖定整張表,它是開銷最小的策略。諸如ALTER TABLE之類的語句會使用表鎖。
行鎖最大程度的支持併發操做,同時也帶來了最大的開銷。InnoDB實現了行鎖。
在MySql中並不僅是用鎖來維護併發控制。併發
事務的隔離級別
事務的概念在此很少介紹。我以爲,也能夠將事務當作是併發中的一部分——事務包含了一組操做,事務和事務之間能夠並行執行。事務和事務之間的併發也和普通的併發操做同樣會共享相同的資源,這樣併發執行的事務之間就會相互影響。根據事務之間影響程度的不一樣,提出了事務的隔離級別這個概念,分別是READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ、SERIALIZABLE。
READ UNCOMMITTED就是一個事務對共享數據的修改立刻就可以被另外一個事務感知到,其實也就是沒有對修改操做作任何特殊處理。
SERIALIZABLE是經過加鎖的方式強制事務串行執行,這樣能夠避免幻讀。但這種方式會帶來大量鎖爭用問題。
READ COMMITTED和REPEATABLE READ是基於MVCC的方式實現的。性能
MVCC多版本併發控制
MySql對於事務之間併發控制的實現並非簡單的使用行級鎖。MySql在讀操做時並不加鎖,只有在寫操做時纔會對修改的資源加鎖。
MVCC保存了數據資源在不一樣時間點上的多個快照。根據事務開始的時間不一樣,每一個事務看到的數據快照版本是不同的。
InnoDB中的MVCC實現:存儲引擎全局維護了一個系統版本號,每開啓一個新的事務,這個系統版本號就會遞增。事務開始時刻的系統版本號,會做爲這個事務自己的版本號。在每行記錄中,存儲引擎又在每行的後面保存兩個隱藏的列,分別保存這一行的開始版本號和過時版本號。在REPEATABLE READ隔離級別下,MVCC的具體操做以下:版本控制
-
INSERT
存儲引擎爲新插入的每一行保存當前的系統版本號做爲這一行的開始版本號。事務 -
UPDATE
存儲引擎會新插入一行記錄,當前的系統版本號就是新記錄行的開始版本號。同時會將原來行的過時版本號設爲當前的系統版本號。資源 -
DELETE
存儲引擎將刪除的記錄行的過時版本號設置爲當前的系統版本號。class -
SELECT
當讀取記錄時,存儲引擎會選取知足下面兩個條件的行做爲讀取結果。並行-
讀取記錄行的開始版本號必須早於當前事務的版本號。也就是說,在當前事務開始以前,這條記錄已經存在。在事務開始以後才插入的行,事務不會看到。數據
-
讀取記錄行的過時版本號必須晚於當前事務的版本號。也就是說,當前事務開始的時候,這條記錄尚未過時。在事務開始以前就已通過期的數據行,該事務也不會看到。di
-
經過上面的描述,能夠看到在存儲引擎中,同一時刻存儲了一個數據行的多個版本。每一個事務會根據本身的版本號和每一個數據行的開始及過時版本號選擇讀取合適的數據行。MVCC只在READ COMMITTED和REPEATABLE READ這兩個級別下工做。