什么是幻讀?
成都創(chuàng)新互聯公司是一家集網站設計制作、成都網站制作、網站頁面設計、網站優(yōu)化SEO優(yōu)化為一體的專業(yè)網絡公司,已為成都等多地近百家企業(yè)提供網站建設服務。追求良好的瀏覽體驗,以探求精品塑造與理念升華,設計最適合用戶的網站頁面。 合作只是第一步,服務才是根本,我們始終堅持講誠信,負責任的原則,為您進行細心、貼心、認真的服務,與眾多客戶在蓬勃發(fā)展的市場環(huán)境中,互促共生。
幻讀指的是一個事務在前后兩次查詢同一個范圍的時候,后一次查詢看到了前一次查詢沒有看到的行。
首先快照讀是不存在幻讀的,只有當前讀(實時讀)才存在幻讀的問題。
幻讀有什么問題?
select ...for update語句就是將相應的數據行鎖住,但是如果存在幻讀,就把for update的語義破壞了。
如何解決幻讀?
產生幻讀的原因是,行鎖只能鎖住行,但是新插入記錄這個動作,要更新的是記錄之間的“間隙”。因此,為了解決幻讀問題,InnoDB只好引入新的鎖,也就是間隙鎖(Gap Lock)。間隙鎖和行鎖合稱 next-key lock , 每個next-key lock是前開后閉區(qū)間 。
總結
如果在transaction1(Tr1)進行一個
select * from table1 where id 4 lock in share mode.
這里會在table1上加一個next_key lock(間隙鎖),基本原理是什么呢?大致是這樣的,內存中有一個lock hash。是一個key(類似于tableid+pageid+offset)到value(所加的鎖)--- 這就是行鎖的原理。所以 id4的話,會給0 1 2 4(假設當前數據庫沒有3)加上行鎖,這樣就保證了不會出現插入id=3.5這種事情的發(fā)生。
Record Lock: 單個行記錄上的鎖
Gap Lock :間隙鎖,鎖定一個范圍,但不包含記錄本身
Next-Key Lock:Gap Lock + Record Lock,鎖定一個范圍,并且包含記錄本身
Record Lock會鎖住索引記錄,如果建表時沒有設置添加索引,Innodb會去鎖定隱式的主鍵。
本文死鎖場景皆為工作中遇到(或同事遇到)并解決的死鎖場景,寫這篇文章的目的是整理和分享,歡迎指正和補充,本文死鎖場景包括:
注 :以下場景隔離級別均為默認的Repeatable Read;
前提 :表 t_user 的 uid 字段創(chuàng)建了唯一索引,并擁有可更新字段age。
場景復現 :
相應業(yè)務案例和解決方案 :
該場景常見于事務中存在for循環(huán)更新某條記錄的情況,死鎖日志顯示 lock_mode X locks rec but not gap waiting (即行鎖而非間隙鎖),解決方案:
表結構 :
場景復現 :
首先查詢表中目前存在的記錄:
執(zhí)行兩個事務的操作:
死鎖原因分析 :
解決方案 :
t_user結構改造為:
場景復現操作(幾率不高) :
假設存在以下數據 :
死鎖分析 :
事務1 :
① 鎖住zone_id=1對應的間隙鎖: zoneId in (1,2)
② 鎖住索引zone_id=1對應的主鍵索引行鎖id = [1,2]
③ 鎖住uid=1對應的間隙鎖: uid in (1, 2)
④ 鎖住uid=1對應的主鍵索引行鎖: id = [1, 3]
事務2 :
① 鎖住zone_id=2對應的間隙鎖: zoneId in (1,2)
② 鎖住索引zone_id=2對應的主鍵索引行鎖id = [3,4]
③ 鎖住uid=2對應的間隙鎖: uid in (1, 2)
④ 鎖住uid=2對應的主鍵索引行鎖: id = [2, 4]
解決方案 :創(chuàng)建聯合索引,使執(zhí)行計劃只會用到一個索引。
測試表結構 :
場景復現操作 :
解決辦法:盡量避免這種插入又回滾的場景。
避免死鎖的原則: