MySQL: 幻讀演示 & 解決幻讀問題
阿新 • • 發佈:2021-07-15
幻讀: select 某記錄是否存在,不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,無法插入,此時就發生了幻讀。
幻讀演示
1. 開啟 A B 視窗, 選擇資料庫 開啟事務
2. A 視窗 先執行一次查詢操作
-- 假設要再新增一條id為3的 資料,在新增之前先判斷是否存在 select * from account where id = 3;
3. B 視窗 插入一條資料 提交事務
INSERT INTO account VALUES(3,'lucy',1000); commit;
4.A 視窗執行 插入操作, 發現報錯. 出現幻讀
A視窗:“見鬼了,我剛才讀到的結果應該可以支援我這樣操作才對啊,為什麼現在不可以”
解決幻讀問題
將事務隔離級別設定到最高 SERIALIZABLE ,以擋住幻讀的發生
如果一個事務,使用了SERIALIZABLE——可序列化隔離級別時,在這個事務沒有被提交之前 ,
其 他的執行緒,只能等到當前操作完成之後,才能進行操作,這樣會非常耗時,
而且會影響資料庫的 效能,資料庫不會使用這種隔離級別
程式碼示例:
1. 恢復資料
DELETE FROM account WHERE id = 3;
2. 開啟A 視窗 將資料隔離級別提升到最高
set global transaction isolation level SERIALIZABLE;
3. 開啟 A B 視窗, 選擇資料庫 開啟事務
4. A 視窗 先執行一次查詢操作
SELECT * FROM account WHERE id = 3;
5. B 視窗插入一條資料
INSERT INTO account VALUES(3,'lucy',1000);
6. A 視窗執行插入操作, 提交事務資料插入成功.
INSERT INTO account VALUES(3,'lucy',1000); commit;
7. B 視窗在 A視窗提交事務之後, 再執行,但是主鍵衝突出現錯誤
總結:
serializable 序列化可以徹底解決幻讀,但是 事務只能排隊執行,嚴重影響效率, 資料庫不會使用這種隔離級別