MySQL 在當(dāng)前讀的情況下,如果看到了其他事務(wù)新插入的一條數(shù)據(jù),這種情況稱為幻讀。
是指一個(gè)事務(wù)在前后兩次查詢同一個(gè)范圍的時(shí)候,后一次查詢看到了前一次查詢沒(méi)有看到的行。
- 在 可重復(fù)讀 的隔離級(jí)別下,普通的查詢時(shí)快照讀,是不會(huì)看到別的事務(wù)插入的數(shù)據(jù)的。因此,幻讀在“當(dāng)前讀” 下才會(huì)出現(xiàn)。
- 幻讀僅指新插入的行。
幻讀的影響
語(yǔ)義上的影響。例如下圖:

sessionA 聲明了“我要把所有 d=5 的行鎖住,不準(zhǔn)別的事務(wù)進(jìn)行再進(jìn)行操作”。而實(shí)際上,這個(gè)語(yǔ)義被破壞了。
數(shù)據(jù)一致性的問(wèn)題。鎖的設(shè)計(jì)師為了保證數(shù)據(jù)的一致性,一致性不只是數(shù)據(jù)庫(kù)內(nèi)部數(shù)據(jù)狀態(tài)的一致性,還包含了數(shù)據(jù)和日志在邏輯上的一致性。
如果出現(xiàn)幻讀,數(shù)據(jù)庫(kù)的binlog 的順序就會(huì)錯(cuò)亂,因?yàn)?binlog 是在事務(wù)提交之后記錄的。如果使用了這樣的binlog 去備庫(kù)執(zhí)行或是克隆一個(gè)庫(kù),就會(huì)出問(wèn)題。
如何解決幻讀
為了解決幻讀,InnoDB 引入了新的鎖,就是間隙鎖(gap lock)。
間隙鎖就是在執(zhí)行當(dāng)前讀的時(shí)候,不止是給數(shù)據(jù)庫(kù)已有的數(shù)據(jù)加上行鎖,還同時(shí)加了間隙鎖,確保無(wú)法插入新的記錄。
間隙鎖只跟“往這個(gè)間隙中插入一條記錄”這個(gè)操作沖突。間隙鎖之間不存在沖突。
間隙鎖與行鎖并稱為 next-key lock。
但是間隙鎖的引入,可能會(huì)導(dǎo)致同樣的語(yǔ)句鎖住了更大的范圍,這其實(shí)是影響了并發(fā)度的。如果兩個(gè)事務(wù)同時(shí)插入一條數(shù)據(jù),而且持有同樣的間隙鎖,就會(huì)產(chǎn)生死鎖。
有的公司會(huì)使用讀提交的隔離級(jí)別,然后把 binlog 的格式設(shè)置為 row,也可以解決間隙鎖會(huì)產(chǎn)生死鎖的問(wèn)題。但是具體的業(yè)務(wù)也需要具體分析。