1. 程式人生 > >悲觀鎖,樂觀鎖,行鎖,表鎖,頁鎖,共享鎖,排他鎖

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

悲觀鎖:

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

行鎖:

  下面演示行鎖,開啟兩個mysql命令列介面,兩個執行緒分別執行如下操作:(左邊先執行) 

   

左邊的執行緒,在事務中通過select for update語句給sid = 1的資料行上了鎖。右邊的執行緒此時可以使用select語句讀取資料,但是如果也使用select for update語句,就會阻塞,使用update,add,delete也會阻塞。 

  當左邊的執行緒將事務提交(或者回滾),右邊的執行緒就會獲取鎖,執行緒不再阻塞: 

此時,右邊的執行緒獲取鎖,左邊的執行緒如果執行類似操作,也會被阻塞:

表鎖: 

   

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

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不一致,就知道有別的執行緒更新了資料,這個時候就會進行業務邏輯的處理。 

   

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