MySQL的樂觀鎖

2021-10-08 06:43:15 字數 2776 閱讀 1400

一、樂觀鎖介紹

樂觀鎖( optimistic locking ) 相對悲觀鎖而言,樂觀鎖假設認為資料一般情況下不會造成衝突,所以在資料進行提交更新的時候,才會正式對資料的衝突與否進行檢查,樂觀鎖適用於大量讀的應用型別,這樣可以提高吞吐量,像資料庫如果提供類似於write_condition機制的其實都是提供的樂觀鎖。類似svn

二、實現方式

1、使用資料版本(version)記錄機制實現,這是樂觀鎖最常用的一種實現方式。何謂資料版本?即為資料增加乙個版本標識,一般是通過為資料庫表增加乙個數字型別的 「version」 欄位來實現。當讀取資料時,將version欄位的值一同讀出,資料每更新一次對此version值加1。當我們提交更新的時候,判斷資料庫表對應記錄的當前版本資訊與第一次取出來的version值進行比對,如果資料庫表當前版本號與第一次取出來的version值相等則予以更新,否則認為是過期資料。

2、樂觀鎖定的第二種實現方式和第一種差不多,同樣是在需要樂觀鎖控制的table中增加乙個字段,名稱無所謂,字段型別使用時間戳(timestamp), 和上面的version類似,也是在更新提交的時候檢查當前資料庫中資料的時間戳和自己更新前取到的時間戳進行對比,如果時間戳一致則ok,否則就是版本衝突。

三、樂觀鎖悲觀鎖區別

悲觀鎖假定其他使用者企圖訪問或者改變你正在訪問、更改的物件的概率是很高的。因此在悲觀鎖的環境中,在你開始改變此物件之前就將該物件鎖住,並且直到你提交了所作的更改之後才釋放鎖。悲觀鎖的缺陷是不論是頁鎖還是行鎖,加鎖的時間可能會很長,這樣可能會長時間的限制其他使用者的訪問,也就是說悲觀鎖的併發訪問性不好。

樂觀鎖則認為其他使用者企圖改變你正在更改的物件的概率是很小的,因此樂觀鎖直到你準備提交所作的更改時才將物件鎖住,當你讀取以及改變該物件時並不加鎖。可見樂觀鎖加鎖的時間要比悲觀鎖短,樂觀鎖可以用較大的鎖粒度獲得較好的併發訪問效能。

比如:如果第二個使用者恰好在第乙個使用者提交更改之前讀取了該物件,那麼當他完成了自己的更改進行提交時,資料庫就會發現該物件已經變化了,這樣,第二個使用者不得不重新讀取該物件並作出更改。在樂觀鎖環境中,會增加併發使用者讀取物件的次數。

版本控制系統

如果資料是可變的,並且無法隔離呢?這種情況下最常用的兩種控制就是樂觀併發控制和悲觀併發控制。

假設小張和小李想要同時修改同乙個檔案。如果使用樂觀鎖,倆人都能開啟檔案進行修改,如果小張先提交了內容,沒有問題,他所做的改變會儲存到伺服器上。但小李提交時就會遇到麻煩,版本控**務器會檢測出兩種修改的衝突,小李的提交會被拒絕,並由小李決定該如何處理這種情況(對於絕大部分版本控制軟體來說,會讀取並標識出小張做的改變,然後由小李決定是否合併)。       

如果使用的是悲觀鎖,小張先檢出(check out)檔案,那麼小李就無法再次檢出同一檔案,直到小張提交了他的改變

使用建議

將樂觀鎖想成一種檢測衝突的手段,而悲觀鎖是一種避免衝突的手段(嚴格來說,樂觀鎖其實不能稱之為「鎖」,但是這個名字已經流傳開了,那就繼續使用吧),樂觀鎖可以提高併發訪問的效率,但是如果出現了衝突只能向上丟擲,然後重來操作一遍。悲觀鎖可以避免衝突的發生,但是會降低併發效率,選擇使用那一種鎖取決於訪問頻率和一旦產生衝突的嚴重性。

如果系統被併發訪問的概率很低,或者衝突發生後的後果不太嚴重(所謂後果應該指被檢測到衝突的提交會失敗,必須重來一次),可以使用樂觀鎖,否則使用悲觀鎖。

樂觀鎖的侷限是只能在提交資料時才發現業務事務將要失敗,而且在某些情況下,發現失敗太遲的代價會很大。乙個方法是使用悲觀鎖,它可以盡早地發現錯誤,但是難以程式設計實現,而且會降低系統的靈活性。

四、mvcc中的實現方式

mysql innodb儲存引擎,實現的是基於多版本的併發控制協議——mvcc (multi-version concurrency control) (注:與mvcc相對的,是基於鎖的併發控制,lock-based concurrency control)。mvcc最大的好處,相信也是耳熟能詳:讀不加鎖,讀寫不衝突。在讀多寫少的oltp應用中,讀寫不衝突是非常重要的,極大的增加了系統的併發效能,這也是為什麼現階段,幾乎所有的rdbms,都支援了mvcc

在innodb中,會在每行資料後新增兩個額外的隱藏的值來實現mvcc,這兩個值乙個記錄這行資料何時被建立,另外乙個記錄這行資料何時過期(或者被刪除)。 在實際操作中,儲存的並不是時間,而是事務的版本號,每開啟乙個新事務,事務的版本號就會遞增。 在可重讀repeatable reads事務隔離級別下:

通過mvcc,雖然每行記錄都需要額外的儲存空間,更多的行檢查工作以及一些額外的維護工作,但可以減少鎖的使用。大多數讀操作都不用加鎖,讀資料操作很簡單、效能很好,並且也能保證只會讀取到符合標準的行,也只鎖住必要行。

在mvcc併發控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當前讀 (current read)。快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。當前讀,讀取的是記錄的最新版本,並且,當前讀返回的記錄都會加上鎖,保證其他事務不會再併發修改這條記錄。

在乙個支援mvcc併發控制的系統中,哪些讀操作是快照讀?哪些操作又是當前讀呢?以mysql innodb為例:

快照讀:簡單的select操作,屬於快照讀,不加鎖。(當然,也有例外,下面會分析) 

當前讀:特殊的讀操作,插入/更新/刪除操作,屬於當前讀,需要加鎖。

所有以上的語句,都屬於當前讀,讀取記錄的最新版本。並且,讀取之後,還需要保證其他併發事務不能修改當前記錄,對讀取記錄加鎖。其中,除了第一條語句,對讀取記錄加s鎖 (共享鎖)外,其他的操作,都加的是x鎖 (排它鎖)。

mysql樂觀鎖實現 mysql樂觀鎖實現

在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 1.丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。2.髒讀 當乙個事務讀取其它完成...

mysql 樂觀鎖實現 mysql 樂觀鎖實現

一 為什麼需要鎖 併發控制 在多使用者環境中,在同一時間可能會有多個使用者更新相同的記錄,這會產生衝突。這就是著名的併發性問題。典型的衝突有 1.丟失更新 乙個事務的更新覆蓋了其它事務的更新結果,就是所謂的更新丟失。例如 使用者a把值從6改為2,使用者b把值從2改為6,則使用者a丟失了他的更新。2....

優化mysql樂觀鎖 mysql樂觀鎖總結和實踐

樂觀鎖介紹 樂觀鎖 optimistic locking 相對悲觀鎖而言,樂觀鎖假設認為資料一般情況下不會造成衝突,所以在資料進行提交更新的時候,才會正式對資料的衝突與否進行檢測,如果發現衝突了,則讓返回使用者錯誤的資訊,讓使用者決定如何去做。那麼我們如何實現樂觀鎖呢,一般來說有以下2種方式 1.使...