您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關如何分析數據庫樂觀鎖、悲觀鎖,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結了以下內容,希望大家根據這篇文章可以有所收獲。
當程序中出現并發的問題時,我們就要有相應的手段保證數據的正確性,防止多個用戶在操作數據的時候,出現和預期數據不一樣的現象,產生臟數據,在數據庫的層面如果沒有做好并發控制,就可能導致臟讀、幻讀和不可重復讀等問題,所以對于并發場景鎖機制的應用是非常有效的,保證了數據的準確性。
當我們要對一個數據庫中的一條數據進行修改的時候,為了避免同時被其他人修改,最好的辦法就是直接對該數據進行加鎖以防止并發。這種借助數據庫鎖機制,在修改數據之前先鎖定,再修改的方式被稱之為悲觀并發控制(又名“悲觀鎖”,Pessimistic Concurrency Control,縮寫“PCC”)。
這樣別的線程讀取該數據的時候就需要等待當前線程釋放鎖,獲得到鎖的線程才能獲得該數據的讀寫權限。從而保證了并發修改數據錯誤的問題。但是由于阻塞原因,所以導致吞吐量不高。悲觀鎖更適用于多寫少讀的情況。
好友A和好友B同時來到銀行,首先好友A獲取到你的余額為0,太窮了。
好友B此時獲取不到你的余額,因此好友B處于阻塞狀態,等待ing…….。
好友A給你的銀行賬號里面匯入1000塊,總額等于money=money+1000。
好友A操作完,此時好友B獲取到你的余額1000塊,然后執行轉賬操作money=money+1000,最后你的余額為2000。
假設轉賬的過程沒有鎖機制
好友A和好友B同時來到銀行,首先好友A獲取到你的余額為0,太窮了。
好友B此時也獲取到你的余額為0,然后給你轉賬1000,總額度變為0+1000=1000。
好友A也給你轉賬1000,總額度變為還是為1000,這結果肯定是不對的。
悲觀鎖,正如其名,它指的是對數據被外界(包括本系統當前的其他事務,以及來自外部系統的事務處理)修改持保守態度(悲觀),因此,在整個數據處理過程中,將數據處于鎖定狀態。悲觀鎖的實現,往往依靠數據庫提供的鎖機制 (也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性,否則,即使在本系統中實現了加鎖機制,也無法保證外部系統不會修改數據)。
即使使用了悲觀鎖,還是存在問題,由于悲觀鎖使所有的訪問者同步進行,大量的訪問就會阻塞,占用系統資源,最后的結果不可料想。此時樂觀鎖的作用就誕生了。
數據庫中,在對任意記錄進行修改前,先嘗試為該記錄加上排他鎖(exclusive locking)。如果加鎖失敗,說明該記錄正在被修改,那么當前查詢可能要等待或者拋出異常。具體響應方式由開發者根據實際需要決定。如果成功加鎖,那么就可以對記錄做修改,事務完成后就會解鎖了。其間如果有其他對該記錄做修改或加排他鎖的操作,都會等待我們解鎖或直接拋出異常。
拿比較常用的MySql Innodb引擎舉例,來說明一下在SQL中如何使用悲觀鎖。要使用悲觀鎖,我們必須關閉MySQL數據庫的自動提交屬性。因為MySQL默認使用autocommit模式(自動提交事務),也就是說,當我們執行一個更新操作后,MySQL會立刻將結果進行提交。
sql語句:set autocommit=0
以網購扣減庫存來說明一下悲觀鎖的使用:
//開啟事務
begin;
select quantity from goods where id=1 for update;
update goods set quantity=2 where id =1;
//提交事務
commit;
以上,在對id = 1的記錄修改前,先通過for update的方式進行加鎖,然后再進行修改。如果以上修改庫存的代碼發生并發,同一時間只有一個線程可以開啟事務并獲得id=1的鎖,其它的事務必須等本次事務提交之后才能執行。這樣我們可以保證當前的數據不會被其它事務修改。
上面我們提到,使用select…for update會把數據給鎖住,不過我們需要注意一些鎖的級別,MySQL InnoDB默認行級鎖。行級鎖都是基于索引的,如果一條SQL語句用不到索引是不會使用行級鎖的,會使用表鎖。
樂觀鎖( Optimistic Locking ) 相對悲觀鎖而言,樂觀鎖假設認為數據一般情況下不會造成沖突,所以在數據進行提交更新的時候,才會正式對數據的沖突與否進行檢測,如果發現沖突了,則讓返回用戶錯誤的信息,讓用戶決定如何去做。由于樂觀鎖沒有了鎖等待,提高了吞吐量,所以樂觀鎖適合多讀少寫的場景。 常見的樂觀鎖實現方式是:版本號version和CAS。
采用上面的例子,使用樂觀鎖加版本號的方式,給數據庫的表增加一個字段version版本號,執行的操作如下:
你的好友A獲取你的余額為0并獲取當前的版本號version=0。
好友B也同時獲取你的余額為0并獲取當前的版本號version=0。
好好友A轉賬后的總額為1000,并使版本號version+1=1。更新到數據庫中。
好友B同時也將金額1000匯進你的賬號中,并使版本號version+1=1,提交事務的時候,發現版本號已被修改,提交事務失敗,更新不成功。
此時好友B需要再次執行轉賬操作,才能給你轉賬成功。
相對于悲觀鎖,在對數據庫進行處理的時候,樂觀鎖并不會使用數據庫提供的鎖機制。一般的實現樂觀鎖的方式就是記錄數據版本。數據版本,為數據增加的一個版本標識。當讀取數據時,將版本標識的值一同讀出,數據每更新一次,同時對版本標識進行更新。當我們提交更新的時候,判斷數據庫表對應記錄的當前版本信息與第一次取出來的版本標識進行比對,如果數據庫表當前版本號與第一次取出來的版本標識值相等,則予以更新,否則認為是過期數據。
使用樂觀鎖就不需要借助數據庫的鎖機制了。樂觀鎖的概念中其實已經闡述了它的具體實現細節。主要就是兩個步驟:沖突檢測和數據更新。其實現方式有一種比較典型的就是CAS。
CAS是項樂觀鎖技術,當多個線程嘗試使用CAS同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程并不會被掛起,而是被告知這次競爭中失敗,并可以再次嘗試。
看完上述內容,你們對如何分析數據庫樂觀鎖、悲觀鎖有進一步的了解嗎?如果還想了解更多知識或者相關內容,請關注億速云行業資訊頻道,感謝大家的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。