程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> MYSQL數據庫 >> MySQL綜合教程 >> 【mysql】關於樂觀鎖,mysql

【mysql】關於樂觀鎖,mysql

編輯:MySQL綜合教程

【mysql】關於樂觀鎖,mysql


一、樂觀鎖介紹

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

悲觀鎖假定其他用戶企圖訪問或者改變你正在訪問、更改的對象的概率是很高的,因此在悲觀鎖的環境中,在你開始改變此對象之前就將該對象鎖住,並且直到你提交了所作的更改之後才釋放鎖。

二、實現方式

1.使用數據版本(Version)記錄機制實現,這是樂觀鎖最常用的一種實現方式。何謂數據版本?即為數據增加一個版本標識,一般是通過為數據庫表增加一個數字類型的 “version” 字段來實現。當讀取數據時,將version字段的值一同讀出,數據每更新一次,對此version值加一。當我們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的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事務隔離級別下:

  • SELECT時,讀取創建版本號<=當前事務版本號,刪除版本號為空或>當前事務版本號。
  • INSERT時,保存當前事務版本號為行的創建版本號
  • DELETE時,保存當前事務版本號為行的刪除版本號
  • UPDATE時,插入一條新紀錄,保存當前事務版本號為行創建版本號,同時保存當前事務版本號到原來刪除的行

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

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

在一個支持MVCC並發控制的系統中,哪些讀操作是快照讀?哪些操作又是當前讀呢?以MySQL InnoDB為例:

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

  • select * from table where ?;


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

  • select * from table where ? lock in share mode;
  • select * from table where ? for update;
  • insert into table values (…);
  • update table set ? where ?;
  • delete from table where ?;

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

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved