MySQL幻讀是指在同一事務(wù)內(nèi),多次執(zhí)行同一個查詢語句,結(jié)果集行數(shù)不同的情況。很明顯,這種情況不應(yīng)該出現(xiàn),因為在同一事務(wù)內(nèi),數(shù)據(jù)不應(yīng)該發(fā)生變化。那么,為什么會出現(xiàn)MySQL幻讀呢?
造成MySQL幻讀的原因是,事務(wù)在讀取某個范圍內(nèi)的數(shù)據(jù)時,另外一個事務(wù)插入了新的數(shù)據(jù),導致原有數(shù)據(jù)的范圍發(fā)生變化,從而導致查詢時出現(xiàn)了新的行。這種情況也稱為“幻象行”,因為它們出現(xiàn)得像是出現(xiàn)了魔法。
幻讀的產(chǎn)生是與事務(wù)隔離級別有關(guān)的,如果使用讀未提交的隔離級別,會使得幻讀更加頻繁發(fā)生。在讀未提交的情況下,對于同一行的數(shù)據(jù),一個事務(wù)可以讀取到另外一個事務(wù)未提交的修改結(jié)果,從而導致幻讀的發(fā)生。在其他隔離級別下,MySQL會對查詢來源進行加鎖,從而防止數(shù)據(jù)幻讀的發(fā)生。
// 例如,以下的SQL語句執(zhí)行兩次,行數(shù)不同,就會出現(xiàn)MySQL幻讀 BEGIN; SELECT * FROM orders WHERE status='unpaid' LOCK IN SHARE MODE; // 另一個事務(wù)插入了一條新的訂單記錄 COMMIT; // 再次執(zhí)行以上語句,發(fā)現(xiàn)結(jié)果集行數(shù)改變了,導致了幻讀