聊一聊MySQL裡的鎖和MVCC

2021-08-20 03:19:44 字數 2009 閱讀 3310

在乙個高併發的資料庫系統裡,可能會遇到多個事務同一時刻修改某條資料的情況,這樣就產生了資源衝突,解決衝突就需要用到鎖。

一、鎖一說到鎖,就可能會聯想到樂觀鎖、悲觀鎖、共享鎖(讀鎖)、排他鎖(互斥鎖/寫鎖)、行級鎖、表級鎖 等一堆名詞,那它們之間到底有什麼區別和聯絡呢?其實很簡單,樂觀鎖和悲觀鎖是一種加鎖的思想;行級鎖和表級鎖是鎖的粒度,表示加鎖的範圍;而共享鎖和排他鎖才是真正的鎖,用來鎖住資料。下面我們分別討論一下它們。

1.1 樂觀鎖和排他鎖

鎖名機制

實現原理

優點缺點

適用場景

樂觀鎖整個資料處理過程都不加鎖,直到處理完準備提交時,才通過版本號檢查資料是否過期

大多是基於資料版本( version )記錄機制實現,即為每條資料增加乙個記錄版本號的字段,讀取資料時,將版本號一同讀出,更新時對此版本號加一,此時若提交的資料版本號大於資料庫表當前版本號,則予以更新,否則認為資料已經被其它事務修改過,需要回滾和重試

避免了加鎖的開銷和死鎖的出現,提高了系統的併發效能

來自外部系統的更新操作不受控制

適用於寫操作比較少,資料衝突較少的場景

悲觀鎖資料處理開始時就對資料加鎖,直到處理完成才釋放鎖

需要利用資料庫本身提供的鎖機制來實現,例如共享鎖、排他鎖

外部系統的更新操作也受控制,最大限度的為資料處理的安全性提供了保證

加鎖開銷大,增加產生死鎖的可能性,大大降低系統的併發效能

適用於寫操作比較多,資料衝突嚴重的場景

1.2 表級鎖和行級鎖

表級鎖和行級鎖是一種鎖的粒度。一般來說,鎖粒度越小,鎖衝突就越少,系統的併發效能就更高,但同時資料庫在管理鎖方面的開銷也越大,當管理鎖的開銷比資料訪問的開銷還要大時,反而可能會影響到系統的效能。

在mysql中,每個儲存引擎都可以有自己的鎖策略,例如myisam引擎僅支援表級鎖,而innodb引擎除了支援表級鎖外,也支援行級鎖(預設)。行級鎖可以最大程度地支援併發處理。

1.3 共享鎖和排他鎖

鎖名機制

共享鎖1.當事務a對某資源加了共享鎖後,其它事務也只能對該資源加共享鎖

2.若想加排他鎖,需等待所有事務釋放共享鎖

3.持有共享鎖的事務,都可以讀取該資源,但不能修改

排他鎖1.當事務a對某資源加了排他鎖後,事務a可以讀取和修改該資源

2.其它事務不能對該資源加任何鎖,直到事務a釋放排他鎖

共享鎖和排他鎖是悲觀鎖不同的實現,它倆都屬於悲觀鎖的範疇。在mysql innodb中,update/insert/delete操作都會自動加排他鎖,普通的select語句不會加任何鎖,如果想加鎖,可以使用下面方式:

select * from table_name where id = 1

lock

in share mode;

-- 顯式加共享鎖

select * from table_name where id = 1

forupdate;

-- 顯式加排他鎖

二、多版本併發控制(mvcc)

不同的資料庫實現mvcc的方式是不一樣的,因為mvcc沒有乙個統一的實現標準,這裡我們只談論mysql innodb中的mvcc。

2.1 為什麼需要mvcc

innodb採用的是兩階段鎖定協議,事務執行過程中,根據需要不斷的加鎖,最後commit或rollback的時候一次性釋放所有鎖,實質上是一種悲觀併發控制(悲觀鎖),而悲觀鎖會降低系統的併發效能。為了提高併發效能,innodb同時還實現了多版本併發控制(mvcc)。

2.2 mvcc的實現原理

簡單來說,mvcc就是同一條資料可以同時存在多個版本:更新資料時,先插入一條新記錄,然後把舊記錄標記為刪除;刪除資料時將記錄標記為刪除;查詢時只查詢事務開始前就已存在的記錄。詳細的實現就不展開講了,網上有很多相關資料,詳情可以參考這個**,或者參閱《高效能mysql第三版》1.4章節。

2.3 mvcc解決的問題

通過了解實現原理,可以看出mvcc解決了這些問題:

聊一聊 MySQL 資料庫中的那些鎖

在軟體開發中,程式在高併發的情況下,為了保證一致性或者說安全性,我們通常都會通過加鎖的方式來解決,在 mysql 資料庫中同樣有這樣的問題,一方面為了最大程度的利用資料庫的併發訪問,另一方面又需要保證每個使用者能以一致的方式讀取和修改資料,就引入了鎖機制。全域性鎖是粒度最大的鎖,基本上也使用不上,就...

聊一聊MyISAM和InnoDB的區別

主要有以下區別 1 mysql預設採用的是myisam。2 myisam不支援事務,而innodb支援。innodb的autocommit預設是開啟的,即每條sql語句會預設被封裝成乙個事務,自動提交,這樣會影響速度,所以最好是把多條sql語句顯示放在begin和commit之間,組成乙個事務去提交...

聊一聊 MYSQL 資料的真刪和假刪

簡單做個小白文描述。真刪,我們就不展開了。該篇文章其實主要是想聊聊 這個假刪 邏輯刪除 既然是對某張表做了假刪,使用 status 那麼在一些業務 查詢裡面 切記切記一定不能忘了,只要使用到 假刪 的資料表,那麼需要帶上 status 0 驗重,字面意思就是說資料唯一,而這個資料的唯一保證 我們常規...