原文 https:// developer.aliyun.com/ar ticle/778217?spm=a2c6h.21072623.J_4429179800.2.5b483e04Kb9ie2&utm_content=g_1000213343
索引和鎖是資料庫中的兩個核心知識點,隔離級别的實作都是通過鎖來完成的
按照鎖顆粒對鎖進行劃分 ?
鎖用來對資料進行鎖定,我們可以從鎖定對象的粒度大小來對鎖進行劃分,分别為行鎖、頁鎖和表鎖。
- 行鎖就是按照行的粒度對資料進行鎖定。鎖定力度小,發生鎖沖突機率低,可以實作的并發度高,但是對于鎖的開銷比較大,加鎖會比較慢,容易出現死鎖情況。
- 頁鎖就是在頁的粒度上進行鎖定,鎖定的資料資源比行鎖要多,因為一個頁中可以有多個行記錄。當我們使用頁鎖的時候,會出現資料浪費的現象,但這樣的浪費最多也就是一個頁上的資料行。頁鎖的開銷介于表鎖和行鎖之間,會出現死鎖。鎖定粒度介于表鎖和行鎖之間,并發度一般。
- 表鎖就是對資料表進行鎖定,鎖定粒度很大,同時發生鎖沖突的機率也會較高,資料通路的并發度低。不過好處在于對鎖的使用開銷小,加鎖會很快。
還有區鎖和資料庫鎖.

每個層級的鎖數量是有限制的,因為鎖會占用記憶體空間,鎖空間的大小是有限的。當某個層級的鎖數量超過了這個層級的門檻值時,就會進行鎖更新。鎖更新就是用更大粒度的鎖替代多個更小粒度的鎖,比如 InnoDB 中行鎖更新為表鎖,這樣做的好處是占用的鎖空間降低了,但同時資料的并發度也下降了。
從資料庫管理的角度對鎖進行劃分
共享鎖和排它鎖
- 共享鎖也叫讀鎖或 S 鎖,共享鎖鎖定的資源可以被其他使用者讀取,但不能修改。在進行SELECT的時候,會将對象進行共享鎖鎖定,當資料讀取完畢之後,就會釋放共享鎖,這樣就可以保證資料在讀取時不被修改。
- 排它鎖也叫獨占鎖、寫鎖或 X 鎖。排它鎖鎖定的資料隻允許進行鎖定操作的事務使用,其他事務無法對已鎖定的資料進行查詢或修改。
- 當我們對資料進行更新的時候,也就是INSERT、DELETE或者UPDATE的時候,資料庫也會自動使用排它鎖,防止其他事務對該資料行進行操作。
意向鎖(Intent Lock),簡單來說就是給更大一級别的空間示意裡面是否已經上過鎖。
從程式員的角度對鎖進行劃分
樂觀鎖樂觀鎖(Optimistic Locking)認為對同一資料的并發操作不會總發生,屬于小機率事件,不用每次都對資料上鎖,也就是不采用資料庫自身的鎖機制,而是通過程式來實作。在程式上,我們可以采用版本号機制或者時間戳機制實作。
-
樂觀鎖的版本号機制
在表中設計一個版本字段 version,第一次讀的時候,會擷取 version 字段的取值。然後對資料進行更新或删除操作時,會執行UPDATE ... SET version=version+1 WHERE version=version。此時如果已經有事務對這條資料進行了更改,修改就不會成功。
-
樂觀鎖的時間戳機制
時間戳和版本号機制一樣,也是在更新送出的時候,将目前資料的時間戳和更新之前取得的時間戳進行比較,如果兩者一緻則更新成功,否則就是版本沖突。
悲觀鎖(Pessimistic Locking)也是一種思想,對資料被其他事務的修改持保守态度,會通過資料庫自身的鎖機制來實作,進而保證資料操作的排它性。
适用場景
- 樂觀鎖适合讀操作多的場景,相對來說寫的操作比較少。它的優點在于程式實作,不存在死鎖問題,不過适用場景也會相對樂觀,因為它阻止不了除了程式以外的資料庫操作。
- 悲觀鎖适合寫操作多的場景,因為寫的操作具有排它性。采用悲觀鎖的方式,可以在資料庫層面阻止其他事務對該資料的操作權限,防止讀 - 寫和寫 - 寫的沖突。
總結
樂觀鎖和悲觀鎖并不是鎖,而是鎖的設計思想。
避免死鎖的發生:
- 如果事務涉及多個表,操作比較複雜,那麼可以盡量一次鎖定所有的資源,而不是逐漸來擷取,這樣可以減少死鎖發生的機率;
- 如果事務需要更新資料表中的大部分資料,資料表又比較大,這時可以采用鎖更新的方式,比如将行級鎖更新為表級鎖,進而減少死鎖産生的機率;
- 不同僚務并發讀寫多張資料表,可以約定通路表的順序,采用相同的順序降低死鎖發生的機率