MySQL 讀快照指的是在某些場(chǎng)景下,當(dāng)我們?cè)谧x取一張表的數(shù)據(jù)時(shí),事務(wù)A 在讀取過(guò)程中,如果另外一個(gè)事務(wù)B 修改了該表的數(shù)據(jù),會(huì)發(fā)生什么?如果事務(wù)A此時(shí)讀取到的是事務(wù)B修改之前的數(shù)據(jù),或者讀取到了修改過(guò)的數(shù)據(jù),那么很可能會(huì)破壞我們系統(tǒng)的數(shù)據(jù)一致性。因此,MySQL 提供了讀快照技術(shù),可以讓我們避免這個(gè)問(wèn)題。
假設(shè)我們有一張名為 user 的表,里面有以下數(shù)據(jù):
+----+-------+--------+ | id | name | age | +----+-------+--------+ | 1 | Tom | 20 | +----+-------+--------+ | 2 | Jack | 25 | +----+-------+--------+
現(xiàn)在我們來(lái)進(jìn)行讀快照的實(shí)現(xiàn)。在執(zhí)行 SELECT 語(yǔ)句時(shí),加上FOR UPDATE
關(guān)鍵字,可以開(kāi)啟事務(wù)并鎖定行,以防止其他事務(wù)修改該行數(shù)據(jù)。
START TRANSACTION; SELECT * FROM user WHERE id = 1 FOR UPDATE; COMMIT;
此時(shí),在執(zhí)行上述 SQL 前,我們先用一個(gè)事務(wù)B 來(lái)修改 user 表。
START TRANSACTION; UPDATE user SET name = 'Lucy' WHERE id = 1; COMMIT;
接著我們執(zhí)行上述 SQL,可以看到我們讀取到的數(shù)據(jù)是修改前的數(shù)據(jù),也就是:
+----+-------+--------+ | id | name | age | +----+-------+--------+ | 1 | Tom | 20 | +----+-------+--------+
因?yàn)楝F(xiàn)在我們開(kāi)啟了事務(wù)并鎖定了行,讀取該行數(shù)據(jù)時(shí)只能讀到我們開(kāi)啟事務(wù)之前的數(shù)據(jù),這就實(shí)現(xiàn)了快照讀。
需要注意的是,FOR UPDATE
會(huì)鎖住行,其他事務(wù)不能修改該行,這樣可能會(huì)引起死鎖,因此需慎重使用。