MySQL是一款常用的開(kāi)源關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),其提供了ACID事務(wù)隔離級(jí)別的支持,其中包括了Repeatable Read(可重復(fù)讀)和Read Committed(已提交讀)兩個(gè)隔離級(jí)別。
在Repeatable Read隔離級(jí)別下,一旦啟動(dòng)了事務(wù),此時(shí)的查詢結(jié)果集會(huì)被緩存下來(lái),即使其他事務(wù)對(duì)數(shù)據(jù)進(jìn)行了修改,也不會(huì)影響該事務(wù)查詢結(jié)果集。然而,由于在該隔離級(jí)別下,如果其他事務(wù)插入新數(shù)據(jù),該事務(wù)再次查詢時(shí)就會(huì)出現(xiàn)幻讀(即看到了其他事務(wù)插入的新數(shù)據(jù)),對(duì)于已存在的數(shù)據(jù),幻讀是不會(huì)發(fā)生的。
但是,在使用Repeatable Read隔離級(jí)別時(shí),如果進(jìn)行了數(shù)據(jù)的修改(新增、刪除、修改等),其他事務(wù)查詢同一數(shù)據(jù)可能會(huì)出現(xiàn)重復(fù)讀現(xiàn)象(即多次查詢結(jié)果相同),但幻讀則不會(huì)出現(xiàn)。因此,實(shí)際上,MySQL的Repeatable Read隔離級(jí)別并不支持幻讀。
beginTransaction(); // 查詢數(shù)據(jù) $sql = "SELECT * FROM user WHERE age<= 20"; foreach ($pdo->query($sql) as $row) { var_dump($row); } // 修改數(shù)據(jù) $sql = "UPDATE user SET age = age + 1 WHERE age<= 20"; $pdo->exec($sql); // 再次查詢數(shù)據(jù) $sql = "SELECT * FROM user WHERE age<= 20"; foreach ($pdo->query($sql) as $row) { var_dump($row); } // 提交事務(wù) $pdo->commit(); ?>
上述代碼展示了Repeatable Read隔離級(jí)別下的重復(fù)讀現(xiàn)象,其中包括了查詢、修改和再次查詢操作。需要注意的是,這里的查詢語(yǔ)句使用的是SELECT * FROM user WHERE age<= 20,因此只查詢了年齡小于等于20的數(shù)據(jù)。
在第一次查詢時(shí),我們可以得到所有年齡小于等于20的數(shù)據(jù),而在修改了其中的數(shù)據(jù)后再次查詢時(shí),我們發(fā)現(xiàn)查詢結(jié)果并沒(méi)有發(fā)生變化,因此沒(méi)有出現(xiàn)幻讀現(xiàn)象。但是,由于我們使用了Repeatable Read隔離級(jí)別,因此重復(fù)讀現(xiàn)象則十分明顯。
綜上所述,MySQL的Repeatable Read隔離級(jí)別并不支持幻讀,但是支持重復(fù)讀現(xiàn)象。因此,在實(shí)際的應(yīng)用場(chǎng)景中,我們需要根據(jù)具體情況選擇合適的事務(wù)隔離級(jí)別。