MySQL InnoDB引擎锁的总结
為什么要鎖
我們開的的各式各樣系統(tǒng)中,系統(tǒng)運行需要CPU、內(nèi)存、I/O、磁盤等等資源。但除了硬資源外,還有最為重要的軟資源:數(shù)據(jù)。
當人們訪問操作我們的系統(tǒng)時,其實歸根是對數(shù)據(jù)的查看與生產(chǎn)。那么對于同一份數(shù)據(jù),如果多個用戶同時對它查看、修改時會出現(xiàn)什么問題呢?這必然會帶來競爭,而為了控制并發(fā)的讀取、修改數(shù)據(jù)會對數(shù)據(jù)造成的不一致、錯亂等問題,數(shù)據(jù)庫引入了鎖的機制。
當然鎖的問題解決了并發(fā)訪問數(shù)據(jù)的問題,而不可避免的會對系統(tǒng)的性能產(chǎn)生負面影響。總結(jié)一下各種鎖的使用場景方便在實踐中更好的運用它從而提升系統(tǒng)性能。
鎖的種類
我們?nèi)粘i_發(fā)中用到最多的存儲引擎是Innodb 與 MyISAM兩種,而 Innodb 現(xiàn)在更多是首選,因此主要是對 Innodb 的說明,MyISAM 跟多是作為一個對比的角色。
?
? MySQL的鎖可以按照多種方式進行劃分,這里使用最常用的兩種方式進行劃分:粒度與使用方式。
需要特別說明的是:樂觀鎖與悲觀鎖并不是數(shù)據(jù)庫中實現(xiàn)的鎖機制,是需要我們自己去實現(xiàn)的。它是一種思想,我們不僅僅可以用在MySQL中,其它地方有需要的也可以用到。而像悲觀鎖它也是利用數(shù)據(jù)庫現(xiàn)有的機制進行實現(xiàn)的。下面先根據(jù)不同分類對說明相關(guān)概念。
按使用方式
樂觀鎖?機制采取了更加寬松的加鎖機制。悲觀鎖大多數(shù)情況下依靠數(shù)據(jù)庫的鎖機制實現(xiàn),以保證操作最大程度的獨占性。但隨之而來的就是數(shù)據(jù)庫性能的大量開銷,特別是對長事務(wù)而言,這樣的開銷往往無法承受。相對悲觀鎖而言,樂觀鎖更傾向于開發(fā)運用。
悲觀鎖?具有強烈的獨占和排他特性。它指的是對數(shù)據(jù)被外界(包括本系統(tǒng)當前的其他事務(wù),以及來自外部系統(tǒng)的事務(wù)處理)修改持保守態(tài)度,因此,在整個數(shù)據(jù)處理過程中,將數(shù)據(jù)處于鎖定狀態(tài)。悲觀鎖的實現(xiàn),往往依靠數(shù)據(jù)庫提供的鎖機制(也只有數(shù)據(jù)庫層提供的鎖機制才能真正保證數(shù)據(jù)訪問的排他性,否則,即使在本系統(tǒng)中實現(xiàn)了加鎖機制,也無法保證外部系統(tǒng)不會修改數(shù)據(jù))。
按粒度
表級鎖?是MySQL中鎖定粒度最大的一種鎖,表示對當前操作的整張表加鎖,它實現(xiàn)簡單,資源消耗較少,被大部分MySQL引擎支持。最常使用的MyISAM與InnoDB都支持表級鎖定。表級鎖分為表共享讀鎖與表獨占寫鎖。
行級鎖?是Mysql中鎖定粒度最細的一種鎖,表示只針對當前操作的行進行加鎖。行級鎖能大大減少數(shù)據(jù)庫操作的沖突。其加鎖粒度最小,但加鎖的開銷也最大。行級鎖分為共享鎖 和 排他鎖。
頁級鎖?是MySQL中鎖定粒度介于行級鎖和表級鎖中間的一種鎖。表級鎖速度快,但沖突多,行級沖突少,但速度慢。所以取了折中的頁級,一次鎖定相鄰的一組記錄。BDB支持頁級鎖。
這里需要說明的是,悲觀鎖是一種思想,它的實現(xiàn)是使用了 共享鎖與排他鎖來實現(xiàn)的。因此悲觀鎖本身并不是MySQL實現(xiàn)的鎖機制,它是我們造出來的一個概念。
InnoDB中加鎖
InnoDB 實現(xiàn)了兩種類型的行鎖,共享鎖(S)與排他鎖(X)。然后由于 InnoDB引擎又支持表級鎖,所以它內(nèi)部又有意向共享鎖(IS)與意向排他鎖(IX)。這兩種表鎖,都是InnoDB內(nèi)部自動處理,換句話說我們寫代碼是無法控制也不需要控制的。我們能控制的是S與X鎖。
為MySQL加鎖
在日常操作中,UPDATE、INSERT、DELETE?InnoDB會自動給涉及的數(shù)據(jù)集加排他鎖,一般的?SELECT?一般是不加任何鎖的。我們可以使用以下方式顯式的為?SELECT?加鎖。
共享鎖:select * form table where id = 10 lock in share mode
排他鎖:select * from table where id = 10 for update
那么什么時候該用共享鎖什么時候用排他鎖呢?
一般來講,共享鎖主要用在需要數(shù)據(jù)依存關(guān)系時來確認某行記錄是否存在,并確保沒有人對這個記錄進行UPDATE或者DELETE操作(包括加鎖的事物也只能讀)。簡單說就是大家都可以讀數(shù)據(jù),但是無法修改(更新或者刪除),因此我認為共享鎖也是悲觀鎖的一種實現(xiàn)。
排他鎖是與共享鎖相對應(yīng),自身加排他鎖的事物能夠自己發(fā)起修改操作,其它事物無法再對該數(shù)據(jù)加共享或者排他鎖。
?
這里需要注意上面說到的一點,由于InnoDB引擎是行鎖,不管我們在這條數(shù)據(jù)上加了共享鎖還是排他鎖,簡單的select語句依然可以使用的,因為默認在InnoDB中select是不加鎖的。
?
這里還有一點,上圖中我們寫到一個?間隙鎖,這是什么東西?比如:當我們用范圍條件而不是相等條件檢索數(shù)據(jù),并請求共享或排他鎖時,InnoDB會給符合條件的已有數(shù)據(jù)的索引項加鎖;對于鍵值在條件范圍內(nèi)但并不存在的記錄,叫做“間隙(GAP)”,InnoDB也會對這個“間隙”加鎖,這種鎖機制就是所謂的間隙鎖(Next-Key鎖)。它存在的主要目的有一個是為了解決幻讀問題,因為RR作為InnoDB的默認事物隔離級別,是存在幻讀問題的,而我們在實際操作中確沒有出現(xiàn),就是因為這里做了處理。
關(guān)于樂觀鎖是如何加鎖的,這個不同系統(tǒng)有不同的實現(xiàn),簡單來說,對每一個數(shù)據(jù)維護一個版本號,每次讀取時把版本號讀取出來,更新時版本號+1。然后更新時將讀取的版本號作為條件,如果有其它事物更新了,那么必然會導(dǎo)致版本號變化,因為本次更新不會成功。這種機制最大程度的保證了并發(fā)。
InnoDB什么時候會鎖表
InnoDB行鎖是通過索引上的索引項來實現(xiàn)的,這一點MySQL與Oracle不同,后者是通過在數(shù)據(jù)中對相應(yīng)數(shù)據(jù)行加鎖來實現(xiàn)的。InnoDB這種行鎖實現(xiàn)特點意味者:只有通過索引條件檢索數(shù)據(jù),InnoDB才會使用行級鎖,否則,InnoDB將使用表鎖!
在實際應(yīng)用中,要特別注意InnoDB行鎖的這一特性,不然的話,可能導(dǎo)致大量的鎖沖突,從而影響并發(fā)性能
總結(jié)
- 悲觀鎖與樂觀鎖是一種思想,而不是數(shù)據(jù)庫鎖機制的實現(xiàn);
- InnoDB的行鎖是基于索引實現(xiàn)的,如果不通過索引訪問數(shù)據(jù),InnoDB會使用表鎖;
- 雖然根據(jù)標準InnoDB的默認事務(wù)隔離級別RR是存在幻讀,但是通過間隙鎖以及MVCC解決了幻讀的問題;
- 間隙鎖的存在會導(dǎo)致并發(fā)插入問題,盡量減少范圍查詢;
- InnoDB的索引設(shè)計非常重要。
轉(zhuǎn)載于:https://www.cnblogs.com/weiqihome/p/9297478.html
總結(jié)
以上是生活随笔為你收集整理的MySQL InnoDB引擎锁的总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 尝试create tech team
- 下一篇: Bootstrap UI 编辑器