隔離級別是在多個事務同時進行更改和執行查詢時,對性能與結果的可靠性、一致性和再現性之間的平衡進行微調的設置。性能
提供了SQL:1992標準中描述的四種事務隔離級別:READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ和SERIALIZABLE。InnoDB默認的隔離級別是REPEATABLE READ。spa
InnoDB使用不一樣的鎖定策略支持這裏描述的每一個事務隔離級別。下面的列表描述了MySQL如何支持不一樣的事務級別。code
1. REPEATABLE READ(可重複讀)orm
這是InnoDB的默認隔離級別。同一個事務中的一致性讀取讀的是第一次讀取時創建的快照。這意味着,若是在同一個事務中發出幾個普通(非鎖定)SELECT語句,這些SELECT語句彼此之間也是一致的。(PS:可重複讀這個級別就是要保證同一個事務中,屢次讀取相同的數據,返回的結果是同樣的。)blog
對於鎖定讀(SELECT with FOR UPDATE or LOCK IN SHARE MODE)、UPDATE 和 DELETE 語句,鎖定取決於語句是使用具備惟一搜索條件的惟一索引,仍是使用範圍類型的搜索條件。索引
2. READ COMMITTED(讀已提交)事務
即便在同一事務中,每一個一致的讀取都將設置並讀取本身的新快照。(PS:對比一下,對於一致性讀,可重複讀是讀取事務中第一次讀取時候創建的快照;而讀已提交,每次都是讀最新的快照)it
對於鎖讀(SELECT with For UPDATE or LOCK IN SHARE MODE)、UPDATE語句和DELETE語句,InnoDB只鎖住索引記錄,而不鎖住它們之間的間隙,從而容許在鎖住的記錄旁邊自由插入新記錄。間隙鎖定僅用於外鍵約束檢查和重複鍵檢查。 io
因爲禁用了間隙鎖,可能會出現幻像問題,由於其餘會話能夠在間隙中插入新行。class
使用READ COMMITTED具備額外的效果:
舉個例子,考慮下面的語句:
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB; INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2); COMMIT;
在這種狀況下,表沒有索引,所以搜索和索引掃描使用隱藏的彙集索引鎖定記錄
假設,第一個會話要執行update語句:
# Session A START TRANSACTION; UPDATE t SET b = 5 WHERE b = 3;
假設,在第一個會話以後,第二個會話也要執行以下update語句:
# Session B UPDATE t SET b = 4 WHERE b = 2;
當InnoDB執行每一個UPDATE時,它首先爲讀取的每一行獲取一個排他鎖,而後決定是否修改它。若是InnoDB沒有修改該行,則釋放鎖。不然,InnoDB會保留鎖直到事務結束。這對事務處理的影響以下。
若是用默認的REPEATABLE READ隔離級別,第一個UPDATE在其讀取的每一行上獲取一個X鎖,而且不釋放其中的任何一個:
x-lock(1,2); retain x-lock x-lock(2,3); update(2,3) to (2,5); retain x-lock x-lock(3,2); retain x-lock x-lock(4,3); update(4,3) to (4,5); retain x-lock x-lock(5,2); retain x-lock
(PS:之因此每一行都加排它鎖,是由於b上沒有惟一索引)
第二個UPDATE在嘗試獲取任何鎖時當即阻塞(由於第一個UPDATE已在全部行上保留了鎖),而且直到第一個UPDATE提交或回滾後才繼續進行:
x-lock(1,2); block and wait for first UPDATE to commit or roll back
若是用READ COMMITTED隔離級別,第一個UPDATE在其讀取的每一行上獲取一個X鎖,併爲未修改的行釋放X鎖:
x-lock(1,2); unlock(1,2) x-lock(2,3); update(2,3) to (2,5); retain x-lock x-lock(3,2); unlock(3,2) x-lock(4,3); update(4,3) to (4,5); retain x-lock x-lock(5,2); unlock(5,2)
可是,若是WHERE條件包含一個索引列,而且InnoDB使用該索引,那麼在獲取和保留記錄鎖時,只考慮索引列。
再看下面一個例子,第一個UPDATE在b = 2的每一行上獲取並保留一個X鎖。第二個UPDATE在嘗試獲取同一記錄上的X鎖時會阻塞,由於它也使用在b列上定義的索引 。
CREATE TABLE t (a INT NOT NULL, b INT, c INT, INDEX (b)) ENGINE = InnoDB; INSERT INTO t VALUES (1,2,3),(2,2,4); COMMIT; # Session A START TRANSACTION; UPDATE t SET b = 3 WHERE b = 2 AND c = 3; # Session B UPDATE t SET b = 4 WHERE b = 2 AND c = 4;
(PS:b列上有索引,這兩條語句在檢索時使用了b列上的索引,所以第一會話在b=2的列上加了X鎖,第一個會話更新b=2時會阻塞)
3. READ UNCOMMITTED(讀未提交)
會出現髒讀,通常不使用
4. SERIALIZABLE(串行化)
此級別相似於REPEATABLE READ,但若是禁用了自動提交,則InnoDB會將全部普通的SELECT語句隱式轉換爲SELECT ... LOCK IN SHARE MODE。