1. 程式人生 > 其它 >MySQL: 幻讀演示 & 解決幻讀問題

MySQL: 幻讀演示 & 解決幻讀問題

幻讀: 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 序列化可以徹底解決幻讀,但是 事務只能排隊執行,嚴重影響效率, 資料庫不會使用這種隔離級別