1. 程式人生 > >Innodb鎖機制總結

Innodb鎖機制總結

1.鎖的目的 1)最大程度提高資料庫的併發訪問 2)確保每個使用者能一致性的讀取和修改資料
2.lock與latch latch主要是保證併發執行緒訪問臨界資源的正確性,其保護的是記憶體資料結構,針對的是執行緒 lock的物件是事務,操作的是資料庫內容
3.鎖(lock)型別 共享鎖:事務在讀行資料時加共享鎖 排他鎖:在修改行資料時加排它鎖 S鎖相容S鎖,不相容X鎖;X鎖不相容其它鎖
意向鎖:也分為意向共享鎖(IS Lock)和意向排它鎖(IX Lock)
意向鎖的目的是為了解決表鎖與行鎖的衝突問題,即如下情況: 事務A鎖住了表中的 一行 ,讓這一行只能讀,不能寫。之後,事務B申請 整個表 的寫鎖。如果事務B申請成功,那麼理論上它就能修改表中的任意一行,這與A持有的行鎖是衝突的。 資料庫需要避免這種衝突,就是說要讓B的申請被阻塞,直到A釋放了行鎖。 資料庫要怎麼判斷這個衝突呢? step1:判斷表是否已被其他事務用表鎖鎖表 step2:判斷表中的每一行是否已被行鎖鎖住。 注意step2,這樣的判斷方法效率實在不高,因為需要遍歷整個表。於是就有了意向鎖。在意向鎖存在的情況下,事務A必須先申請表的意向共享鎖,成功後再申請一行的行鎖。在意向鎖存在的情況下,上面的判斷可以改成
step1:不變 step2:發現表上有意向共享鎖,說明表中有些行被共享行鎖鎖住了,因此,事務B申請表的寫鎖會被阻塞。 注意:申請意向鎖的動作是資料庫完成的,就是說,事務A申請一行的行鎖的時候,資料庫會自動先開始申請表的意向鎖,不需要我們程式設計師使用程式碼來申請,同時意向鎖是意向鎖之間不會衝突, 因為意向鎖僅僅代表要對某行記錄進行操作。在加行鎖時,會判斷是否衝突。
4. 一致性非鎖定 ( Multi Version Concurrency Control,MVCC)(共享鎖相容排它鎖的原因) 一致性非鎖定讀是指Innodb儲存引擎通過行多版本控制的方式來讀取當前資料庫的行資料。
(讀不加鎖,讀寫不衝突。在讀多寫少的OLTP應用中,讀寫不衝突是非常重要的,極大的增加了系統的併發效能) 如果一個事務讀取的行正在執行DELETE或UPDATE操作,這時事務不會阻塞等待鎖釋放,而是直接讀取行的快照資料。快照資料指的是該行的之前版本資料,是通過undo段來實現的。 不同的隔離級別對快照資料的定義不同: 在事務隔離級別RC(讀已提交)和RR(可重複讀)下,InnoDB儲存引擎引擎使用非鎖定的一致性讀。然而,對於快照資料的定義卻不相同。在rc事務隔離級別下,對於快照資料,非一致性讀總是被鎖定行的最新一份快照資料.而在RR事務隔離級別下,對於快照資料,非一致性讀總是讀取事務開始(讀取快照資料的事務,目的是保證可重複讀)時的行資料版本。 (參見: https://www.cnblogs.com/olinux/p/5174888.html )
5.一致性鎖定 在某些情況下,使用者需要顯式地對資料庫讀取操作進行加鎖以保證資料邏輯的一致性, Innodb支援兩種加鎖語句: select ......for update:對行資料加X鎖,其他事務不能對行資料進行操作 select ......lock in share mode:對行資料加S鎖
6. 自增長與鎖 對於包含自增列的表,當對其插入時,會根據自增計數器的值加1並賦予給自增長列。 對於含自增長的表來說,插入包含兩種型別:1)simple insert即在插入操作之前就可以確定插入的行數,對於這種並不會使用鎖,而是使用互斥量對記憶體計算器進行累加操作 2)bulk insert即使用傳統表鎖,AUTO-INC Locking方式不是在一個事務完成後才釋放表,而是在插入完成就釋放 (保證自增列順序)
7.外來鍵與鎖 對於外來鍵值的插入與更新,需要首先查詢父表記錄,對父表不是採用非鎖定讀,而採用鎖定讀,對其主動加s鎖(share mode),這樣父表就不能加X鎖。
8. 行鎖的三種演算法 innodb的行鎖是通過給索引項加鎖實現的,這就意味著只有通過索引條件檢索資料時,innodb才使用行鎖 Record Lock:單個記錄上的鎖(當查詢索引含唯一屬性時) Gap Lock:間隙鎖,鎖定一個範圍,但不包括記錄本身 Next-Key Lock: 鎖定一個範圍,包括記錄本身(Innodb對行查詢採用此演算法),該演算法鎖定的區間為左閉右開區間[,) 注:如果檢索條件沒有使用索引,將會採用表鎖 為何使用Next-key Lock? 主要是為了解決幻讀問題,所謂幻讀指的是在同一事務下,執行 兩次同樣的sql語句 得到的結果不同(在RR級別下才能解決幻讀) 對於此表而言, id為主鍵,number欄位上有非唯一索引的二級索引,有什麼方式可以讓該表不能再插入number=5的記錄? 根據上面生活中的例子,我們自然而然可以想到,只要控制幾個點,number=5 之前 不能插入記錄,number=5現有的記錄 之間 不能再插入新的記錄,number=5 之後 不能插入新的記錄,那麼新的number=5的記錄將不能被插入進來。 那麼,mysql是如何控制number=5之前,之中,之後不能有新的記錄插入呢(防止幻讀)? 答案是用間隙鎖,在RR級別下,mysql通過間隙鎖可以實現鎖定number=5之前的間隙,number=5記錄之間的間隙,number=5之後的間隙,從而使的新的記錄無法被插入進來 參考: http://blog.csdn.net/lz710117239/article/details/78705082
9.和鎖有關的幾個概念 髒讀:一個事務讀到另一個事務未提交的資料(在read committed中解決) 不可重複讀:讀取到了另一個事務已提交的對某資料的 修改 幻讀:由於另一個事務 增加和刪除 ,使得兩次讀取的 記錄數不同 不可重複讀和幻讀的區別於 如何通過鎖機制來解決他們產生的問題 在可重複讀中,該sql第一次讀取到資料後,就將這些資料加鎖,其它事務無法修改這些資料,就可以實現可重複 讀了。但這種方法卻無法鎖住insert的資料,所以當事務A先前讀取了資料,或者修改了全部資料,事務B還是可以insert資料提交,這時事務A就會 發現莫名其妙多了一條之前沒有的資料,在innodb中採用 Next-Key Lock 丟失更新:如果多個事務操作,基於同一個查詢結果(獲取時相同)對錶中的記錄進行修改,那麼後修改的記錄將會覆蓋前面修改的記錄,前面的修改就丟失掉了,這就叫做更新丟失 採用最高隔離級別:Serializable(可序列化)來解決丟失更新的問題 所謂可序列化是在 讀取的每一行資料上都加鎖 強制事務序列執行,使之不可能相互衝突