天天看點

2020-09-22MySQL鎖機制概述

MySQL鎖機制概述

什麼是鎖,為什麼使用鎖

鎖是計算機協調多個程序或純線程并發通路某一資源的機制。

在資料庫中,除傳統的計算資源(CPU、RAM、I/O)的争用以外,資料也是一種供許多使用者共享的資源。如何保證資料并發通路的一緻性、有效性是所在有資料庫必須解決的一個問題,鎖沖突也是影響資料庫并發通路性能的一個重要因素。從這個角度來說,鎖對資料庫而言顯得尤其重要,也更加複雜。

防止更新丢失,并不能單靠資料庫事務控制器來解決,需要應用程式對要更新的資料加必要的鎖來解決。

鎖的運作

事務T在對某個資料對象(如表、記錄等)操作之前,先向系統送出請求,對其加鎖,加鎖後事務T就對資料庫對象有一定的控制,在事務T釋放它的鎖之前,其他事務不能更新此資料對象。

鎖定機制分類

鎖定機制就是資料庫為了保證資料的一緻性而使各種共享資源在被并發通路通路變得有序所設計的一種規則。

MySQL資料庫由于其自身架構的特點,存在多種資料存儲引擎,每種存儲引擎所針對的應用場景特點都不太一樣,為了滿足各自特定應用場景的需求,每種存儲引擎的鎖定機制都是為各自所面對的特定場景而優化設計,是以各存儲引擎的鎖定機制也有較大差別。

按封鎖類型分類:資料對象可以是表可以是記錄

  • 排他鎖:(又稱寫鎖,X鎖):會阻塞其他事務讀和寫。

    若事務T對資料對象A加上X鎖,則隻允許T讀取和修改A,其他任何事務都不能再對加任何類型的鎖,直到T釋放A上的鎖。這就保證了其他事務在T釋放A上的鎖之前不能再讀取和修改A。

  • 共享鎖:(又稱讀取,S鎖):會阻塞其他事務修改表資料。

    若事務T對資料對象A加上S鎖,則其他事務隻能再對A加S鎖,而不能X鎖,直到T釋放A上的鎖。這就保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

    X鎖和S鎖都是加在某一個資料對象上的,也就是資料的粒度。

按封鎖的資料粒度分類:行級鎖定、表級鎖定

行級鎖定(row-level):開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖沖突的機率最低,并發度也最高。

行級鎖定最大的特點就是鎖定對象的顆粒度很小,也是目前各大資料庫管理軟體所實作的鎖定顆粒度最小的。

由于鎖定顆粒度很小,是以發生鎖定資源争用的機率也最小,能夠給予應用程式盡可能大的并發處理能力而提高一些需要高并發應用系統的整體性能。

行級鎖隻在存儲引擎層實作,而MySQL伺服器層沒有實作,伺服器層完全不了解存儲引擎中的鎖實作。

缺陷:由于鎖定資源的顆粒度很小,是以每次擷取鎖和釋放鎖需要做的事情也更多,帶來的消耗自然也就更大了。此外,行級鎖定也最容易發生死鎖。

行級鎖可以最大程度地支援并發處理(同時也帶來了最大的鎖開銷)。

表級鎖定(table-level):開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖沖突的機率最高,并發度最低。

表級别的鎖定是MySQL各存儲引擎中最大顆粒度的鎖定機制。

該鎖定機制最大的特點是實作邏輯非常簡單,帶來的系統負面影響最小。

是以擷取鎖和釋放鎖的速度很快。由于表級鎖一次會将整個表鎖定,是以可以很好的避免困擾我們的死鎖問題。

缺陷:鎖定顆粒度大所帶來最大的負面影響就是出現鎖定資源争用的機率也會最高,緻使并發度大打折扣。

頁級鎖定(page-level):(MySQL特有)開銷和加鎖時間界于表鎖和行鎖之間;會出現死鎖;鎖定粒度界于表鎖和行鎖之間,并發度一般。

頁級鎖定是MySQL中比較獨特的一種鎖定級别,在其他資料庫管理軟體中也并不是太常見。

頁級鎖定的特點是鎖定顆粒度介于行級鎖定與表級鎖之間,是以擷取鎖定所需要的資源開銷,以及所能提供的并發處理能力也同樣是介于上面二者之間。

缺陷:頁級鎖定和行級鎖定一樣,會發生死鎖。

樂觀鎖和悲觀鎖的思想

在資料庫的鎖機制中介紹過,資料庫管理系統(DBMS)中的并發控制的任務是確定在多個事務同時存取資料庫中同一資料時不破壞事務的隔離性和統一性以及資料庫的統一性。

樂觀并發控制(樂觀鎖)和悲觀并發控制(悲觀鎖)是并發控制主要采用的技術手段。

悲觀鎖

在關系資料庫管理系統裡,悲觀并發控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)是一種并發控制的方法。

它可以阻止一個事務以影響其他使用者的方式來修改資料。如果一個事務執行的操作都某行資料應用了鎖,那隻有當這個事務把鎖釋放,其他事務才能夠執行與該鎖沖突的操作。

悲觀并發控制主要用于資料争用激烈的環境,以及發生并發沖突時使用鎖保護資料的成本要低于復原事務的成本的環境中。

悲觀鎖,正如其名,它指的是對資料被外界(包括本系統目前的其他事務,以及來自外部系統的事務處理)修改持保守态度(悲觀),是以,在整個資料處理過程中,将資料處于鎖定狀态。

悲觀鎖的實作,往往依靠資料庫提供的鎖機制 (也隻有資料庫層提供的鎖機制才能真正保證資料通路的排他性,否則,即使在本系統中實作了加鎖機制,也無法保證外部系統不會修改資料)

在資料庫中,悲觀鎖的流程如下:

在對任意記錄進行修改前,先嘗試為該記錄加上排他鎖(exclusive locking)。

如果加鎖失敗,說明該記錄正在被修改,那麼目前查詢可能要等待或者抛出異常。 具體響應方式由開發者根據實際需要決定。

如果成功加鎖,那麼就可以對記錄做修改,事務完成後就會解鎖了。

其間如果有其他對該記錄做修改或加排他鎖的操作,都會等待我們解鎖或直接抛出異常。

MySQL InnoDB中使用悲觀鎖

要使用悲觀鎖,我們必須關閉MySQL資料庫的自動送出屬性,因為MySQL預設使用autocommit模式,也就是說,當你執行一個更新操作後,MySQL會立刻将結果進行送出。

set autocommit=0;

1

悲觀鎖優點與不足

悲觀并發控制實際上是“先取鎖再通路”的保守政策,為資料處理的安全提供了保證。- 但是在效率方面,處理加鎖的機制會讓資料庫産生額外的開銷

還有增加産生死鎖的機會

另外,在隻讀型事務進行中由于不會産生沖突,也沒必要使用鎖,這樣做隻能增加系統負載

還有會降低了并行性,一個事務如果鎖定了某行資料,其他事務就必須等待該事務處理完才可以處理那行資料

樂觀鎖

在關系資料庫管理系統裡,樂觀并發控制(又名“樂觀鎖”,Optimistic Concurrency Control,縮寫“OCC”)是一種并發控制的方法。

它假設多使用者并發的事務在處理時不會彼此互相影響,各事務能夠在不産生鎖的情況下處理各自影響的那部分資料。

在送出資料更新之前,每個事務會先檢查在該事務讀取資料後,有沒有其他事務又修改了該資料。

如果其他事務有更新的話,正在送出的事務會進行復原。

樂觀事務控制最早是由孔祥重(H.T.Kung)教授提出。

樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認為資料一般情況下不會造成沖突,是以在資料進行送出更新的時候,才會正式對資料的沖突與否進行檢測,如果發現沖突了,則讓傳回使用者錯誤的資訊,讓使用者決定如何去做。

相對于悲觀鎖,在對資料庫進行處理的時候,樂觀鎖并不會使用資料庫提供的鎖機制。一般的實作樂觀鎖的方式就是記錄資料版本。

資料版本:為資料增加的一個版本辨別。當讀取資料時,将版本辨別的值一同讀出,資料每更新一次,同時對版本辨別進行更新。當我們送出更新的時候,判斷資料庫表對應記錄的目前版本資訊與第一次取出來的版本辨別進行比對,如果資料庫表目前版本号與第一次取出來的版本辨別值相等,則予以更新,否則認為是過期資料。

實作資料版本有兩種方式,第一種是使用版本号,第二種是使用時間戳。

樂觀鎖使用CAS(Compare And Swep)操作保證資料一緻性

使用版本号實作樂觀鎖

使用版本号時,可以在資料初始化時指定一個版本号,每次對資料的更新操作都對版本号執行+1操作。并判斷目前版本号是不是該資料的最新的版本号。

樂觀鎖優點與不足

樂觀并發控制相信事務之間的資料競争(data race)的機率是比較小的,是以盡可能直接做下去,直到送出的時候才去鎖定,是以不會産生任何死鎖。

但如果直接簡單這麼做,還是有可能會遇到不可預期的結果,例如兩個事務都讀取了資料庫的某一行,經過修改以後寫回資料庫,這時就遇到了問題。

鎖粒度

一種提高共享資源并發性的方式就是讓鎖對象更有選擇性。

盡量隻鎖定需要修改的部分資料,而不是所有的資源。

更理想的方式是,隻對修改的資料片進行精确的鎖定。

任何時候,在給定的資源上,鎖定的資料量越少,則系統的并發程度越高,隻要互相之間不發生沖突即可。

但是加鎖也需要消耗資源,鎖的各種操作,包括獲得鎖、檢查鎖是否已經解除、釋放鎖等,都會增加系統的開銷。如果系統花費大量的時間來管理鎖,而不是存取資料,那麼系統的性能可能會是以受到影響。

所謂的鎖政策,就是在鎖的開銷和資料的安全性之間尋求平衡。