RC(讀已提交)和 RR(可重復讀)隔離級別下不同的查詢語句行為不同,讀取到的數(shù)據(jù)可能不同,以下是詳細分析:
RC(讀已提交)隔離級別
1. select?*?from table where id = 1?for update:
讀取類型:不管是否在事務中執(zhí)行for update,這都是一種當前讀,能確保讀取的數(shù)據(jù)是最新的,因為?for update 會對符合條件的記錄加排他鎖。
因為RC級別下是每次執(zhí)行for update都會新生成讀視圖,事務每次執(zhí)行查詢操作,都會讀取最新已提交的數(shù)據(jù),可以讀到其他事務已提交的修改。
2. select?*?from table where id = 1:
讀取類型:快照讀(一致性讀),基于?MVCC讀視圖讀取的是事務開始時的快照版本。跟?for update一樣,可以看到其他事務已提交的修改。
當where定位列id不是索引時,需要進行全表掃描,會涉及到回庫操作。對于?for update 語句,會對全表掃描到的符合條件的記錄加鎖,性能較差。對于普通的 select 語句,會根據(jù)MVCC機制,根據(jù)undo log版本鏈讀取相應的事務版本數(shù)據(jù),雖然不加鎖但由于需要掃描全表,性能也會受到影響。
RR(可重復讀)隔離級別
1. select?*?from table where id = 1?for update:
讀取類型:當前讀。因為for update 對符合條件的記錄加鎖,確保讀取的數(shù)據(jù)是最新的,并且加鎖。
可以讀取到其他事務已提交的修改,在事務內(nèi),第一次執(zhí)行完?for update后,后續(xù)的?for update 讀取會看到相同的已修改結(jié)果,不會看到其他事務新的修改。因為加鎖,其他事務無法修改,會阻塞或者報錯。
與RR級別的區(qū)別,可以參考如下事務:
begin;
select?*?from?table?where?id?=?1?for?update;
...
select?*?from?table?where?id?=?1?for?update;
commit;
如果是RC級別,第一次執(zhí)行for update時會對滿足id = 1 的記錄加鎖,如果?id 是主鍵或唯一索引,會加行鎖。當該語句執(zhí)行完畢,鎖會被釋放,然后第二次執(zhí)行for update會繼續(xù)加鎖,那么兩次讀取之間就可能讀到其他事務已提交的修改內(nèi)容。
而RR級別第一次執(zhí)行for update時會對滿足 id = 1 的記錄加鎖,一直到事務結(jié)束。因此RR級別事務一致性較高,而性能較低。
2. select?*?from table where id = 1:
讀取類型:快照讀(一致性讀),基于事務開始時創(chuàng)建的快照進行讀取。
只能讀取到事務開始時的數(shù)據(jù)快照,不能讀取到事務開始后其他事務已提交的修改,保證了在同一事務內(nèi)的可重復讀特性。