您好,登錄后才能下訂單哦!
小編給大家分享一下MySQL中幻讀及消除的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
MySQL有四級事務隔離級別:
讀未提交 READ-UNCOMMITTED: 存在臟讀,不可重復讀,幻讀的問題
讀已提交 READ-COMMITTED:不存在臟讀,但存在不可重復讀,幻讀問題
可重復讀 REPEATABLE-READ:不存在臟讀,不可重復讀問題,但存在幻讀問題
序列化SERIALIZABLE:解決臟讀,不可重復讀,幻讀問題,但完全串行執行,性能最低
幻讀錯誤的理解:說幻讀是事務A 執行兩次 select 操作得到不同的數據集,即 select 1 得到10條記錄,select 2 得到11條記錄。這其實并不是幻讀,這是不可重復讀的一種,只會在 R-U R-C 級別下出現,而在 mysql 默認的 RR 隔離級別是不會出現的。
這里給出我對幻讀的理解:
幻讀,并不是說事務中多次讀取獲取的結果集不同,幻讀更重要的是某次的 select 操作得到的結果集所表征的數據狀態無法支撐后續的業務操作。更為具體一些:select 記錄不存在,準備插入此記錄,但執行 insert 時發現此記錄已存在,無法插入,如同產生了幻覺
舉個例子可能會簡化理解:
mysql> show create table user\G *************************** 1. row *************************** Table: user Create Table: CREATE TABLE `user` ( `id` int(11) NOT NULL, `name` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
分別開啟兩個事務T1 & T2,并設置其隔離級別為Reaptable-Read:
T1:
mysql> set global transaction isolation level repeatable read; mysql> begin; mysql> select * from user; mysql> insert into user values (1, 'jeff'); ERROR 1062 (23000): Duplicate entry '1' for key 'PRIMARY' mysql> select * from user;
T2:
mysql> set global transaction isolation level repeatable read; mysql> begin; mysql> insert into user values (1, 'jeff'); mysql> commit;
T1 事務檢測表中是否有 id 為 1 的記錄,沒有則插入
T2 插入干擾記錄,造成T1出現幻讀。
上例中需要確保T1事務執行begin后才開始執行事務T2。
上例中T1就發生了幻讀,因為 T1讀取的數據狀態與后面的動作發生了語義上的沖突:查詢的時候明明提示記錄不存在,插入的時候去提示主鍵重復,類似于出現幻影,因而稱之為幻讀。
MySQL當前有兩種方式可以消除幻讀:
1. 通過對select操作手動加行X鎖(SELECT ... FOR UPDATE )。原因是InnoDB中行鎖鎖定的
是索引,縱然當前記錄不存在,當前事務也會獲得一把記錄鎖(記錄存在就加行X鎖,不
存在就加next-key lock間隙X鎖),這樣其他事務則無法插入此索引的記錄,杜絕幻
讀。
2. 進一步提升隔離級別為SERIALIZABLE
測試一下效果
mysql> begin; mysql> select * from user where id = 2 for update; mysql> insert into user values (2, 'tony'); mysql> commit;
T2:
mysql> begin; mysql> insert into user values (2, 'jimmy'); ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
現在T1查詢時攜帶了for update,在Innodb內會對該索引加鎖(即使當前不存在),于是事務T2的insert會被阻塞直到T1顯示提交,這樣T1成功了,對于T1來說,幻讀確實被消除了,但T2的插入會報主鍵重復,這也符合預期。
至于另外一種提升隔離級別消除幻讀的方式感興趣的可以自己嘗試,這里不再重復,其本質是類似的,只是讓系統代替了手工加鎖。
RR作為 mysql 事務默認隔離級別,是事務安全與性能的折中,正確認識幻讀后,開發者便可以根據需求自行決定是否需要防止幻讀。
SERIALIZABLE則是悲觀的認為幻讀時刻都會發生,故會自動的隱式的對事務所需資源加排它鎖,其他事務訪問此資源會被阻塞等待,故事務是安全的,但需要認真考慮性能。
InnoDB的鎖是針對索引,這點需要引起注意。對行記錄加鎖,如果存在,加X鎖,否則會加 next-key lock / gap 鎖 / 間隙鎖,故InnoDB可以實現事務對某記錄的預先占用,只要本事務還在,其他事務就別想占有它。關于鎖,后面還會再有專門的文章討論。
以上是“MySQL中幻讀及消除的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。