以前在學習《數據庫概論》這門課程的時候,了解到在可重復讀這個隔離級別下,一個事務內同一個SELECT查詢的多次執行會返回相同的結果,而這個是對查詢返回的記錄加共享鎖來實現的。這樣,別的事務如果要更新相同的記錄的話就必要要等前一個事務先釋放鎖。說白了,這就是通過數據庫三級封鎖協議(三級封鎖協議:在一級封鎖協議的基礎上,事務T在讀取數據R之前,必須先對其加上S鎖,直到事務結束後才釋放。三級封鎖協議可以防止丟失更新、髒讀和不可重復讀)實現的。
但是最近在Mysql數據庫上測試的時候,發現一個事務在可重復讀隔離級別下查詢了某個記錄,在沒有提交前,別的事務居然可以更新、刪除這個記錄並且順利地提交,而且在原事務內再次查詢的時候,記錄還和第一次返回一樣。開始覺得太不可思議了,這和自己的理解完全不一樣,上網查閱了相關的資料後才明白,原來Mysql使用了Multi-Version Concurrent Controll多版本並發控制的技術來實現非阻塞式讀的。
MySQL InnoDB使用MVCC來實現非阻塞式讀,在這個模式下,數據庫會為每個數據記錄維護多個版本。在可重復讀隔離級別下,事務第一次查詢記錄的時候,會記錄下一個時間點,在該事務內如果再次(可是以不同的SELECT)查詢相同的數據的話,事務只會取時間點前的記錄版本,這樣在不需要對數據加鎖的情況下就實現了可重復讀的隔離級別了,而且並發性能更好。在同一事務內多次查詢同一數據,也不是就返回一個固定的記錄版本,如果事務先查詢了某個記錄,隨後自己又更新了這個數據,等再查詢該數據的話,返回的就是自己更新過後的數據版本了。
對於讀已提交這個隔離級別,事務內的查詢操作總是會取數據最新的有效版本,即最新的、別的事務已經提交的內容。通過MVCC,事務內的查詢操作(這裡排除SELECT FOR UPDATE和SELECT LOCK IN SHARE MODE兩種情況)就不需要對數據加任何鎖了,這樣,別的事務就可以在不影響原事務的前提下自由的操作這些記錄,極大的提升了並發性能。