悲觀鎖,樂觀鎖,行鎖,表鎖,頁鎖,共享鎖,排他鎖

最近在看 大數據量下高併發同步問題,然後看到了悲觀鎖,樂觀鎖,然後又看到了其他的鎖,有點懵,然後就查資料學習。

悲觀鎖:

  顧名思義,很悲觀,就是每次拿數據的時候都認爲別的線程會修改數據,所以在每次拿的時候都會給數據上鎖。上鎖之後,當別的線程想要拿數據時,就會阻塞,直到給數據上鎖的線程將事務提交或者回滾。傳統的關係型數據庫裏就用到了很多這種鎖機制,比如行鎖,表鎖,共享鎖,排他鎖等,都是在做操作之前先上鎖。

共享鎖 又稱爲讀鎖,簡稱S鎖,顧名思義,共享鎖就是多個事務對於同一數據可以共享一把鎖,都能訪問到數據,但是隻能讀不能修改。

排他鎖 又稱爲寫鎖,簡稱X鎖,顧名思義,排他鎖就是不能與其他所並存,如一個事務獲取了一個數據行的排他鎖,其他事務就不能再獲取該行的其他鎖,包括共享鎖和排他鎖,但是獲取排他鎖的事務是可以對數據就行讀取和修改。

對於共享鎖大家可能很好理解,就是多個事務只能讀數據不能改數據,對於排他鎖大家的理解可能就有些差別,我當初就犯了一個錯誤,以爲排他鎖鎖住一行數據後,其他事務就不能讀取和修改該行數據,其實不是這樣的。排他鎖指的是一個事務在一行數據加上排他鎖後,其他事務不能再在其上加其他的鎖。MySQL InnoDB引擎默認的修改數據語句,update,delete,insert都會自動給涉及到的數據加上排他鎖,select語句默認不會加任何鎖類型,如果加排他鎖可以使用select …for update語句,加共享鎖可以使用select … lock in share mode語句。所以加過排他鎖的數據行在其他事務種是不能修改數據的,也不能通過for update和lock in share mode鎖的方式查詢數據,但可以直接通過select …from…查詢數據,因爲普通查詢沒有任何鎖機制。

1排他鎖和其他鎖不能共存

2innoDB引擎.默認對update,delete,insert加排他鎖,select語句默認不加鎖

3共享鎖可以和其他鎖共存

表鎖:
  
  上述例子中,如果使用如下語句就是使用的表鎖:

select * from student for update;

頁鎖:
  
  行鎖鎖指定行,表鎖鎖整張表,頁鎖是折中實現,即一次鎖定相鄰的一組記錄。
  
共享鎖:
  
  共享鎖又稱爲讀鎖,一個線程給數據加上共享鎖後,其他線程只能讀數據,不能修改。
  
排他鎖:
  
  排他鎖又稱爲寫鎖,和共享鎖的區別在於,其他線程既不能讀也不能修改。


樂觀鎖:
  
  樂觀鎖其實不會上鎖。顧名思義,很樂觀,它默認別的線程不會修改數據,所以不會上鎖。只是在更新前去判斷別的線程在此期間有沒有修改數據,如果修改了,會交給業務層去處理。
  常用的實現方式是使用版本戳,例如在一張表中添加一個整型字段version,每更新version++,比如某個時刻version=1,線程A讀取了此version=1,線程B也讀取了此version=1,當線程A更新數據之前,判斷version仍然爲1,更新成功,version++變爲2,但是當線程B再提交更新時,發現version變爲2了,與之前讀的version=1不一致,就知道有別的線程更新了數據,這個時候就會進行業務邏輯的處理。

舉例:

下單操作包括3步驟:

1.查詢出商品信息

select (status,status,version) from t_goods where id=#{id}

2.根據商品信息生成訂單

3.修改商品status爲2

update t_goods 

set status=2,version=version+1

where id=#{id} and version=#{version};


除了自己手動實現樂觀鎖之外,現在網上許多框架已經封裝好了樂觀鎖的實現,如hibernate,需要時,可能自行搜索"hiberate 樂觀鎖"試試看。

  
通常情況下,寫操作較少時,使用樂觀鎖,寫操作較多時,使用悲觀鎖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章