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