10、數據庫鎖

加鎖是爲了保證數據的一致性程序員

1、按照鎖粒度進行劃分

    缺點 優勢
表鎖 數據表進行鎖定
  • 鎖定粒度很大
  • 發生鎖衝突的機率也會較高
  • 數據訪問的併發度低
  • 對鎖的使用開銷小,加鎖會很快
頁鎖 數據頁的粒度上進行鎖定
  • 鎖定的數據資源比行鎖要多,一個頁中能夠有多個行記錄
  • 會出現數據浪費的現象,但這樣的浪費最多也就是一個頁上的數據行
  • 頁鎖的開銷介於表鎖和行鎖之間,會出現死鎖
  • 鎖定粒度介於表鎖和行鎖之間
  • 會出現死鎖
  • 併發度通常
行鎖 行的粒度對數據進行鎖定
  • 鎖的開銷比較大
  • 加鎖會比較慢,
  • 容易出現死鎖狀況
  • 鎖定力度小
  • 發生鎖衝突機率低
  • 能夠實現的併發度高

  • 每一個層級的鎖數量是有限制的,鎖會佔用內存空間,鎖空間的大小是有限的
  • 當某個層級的鎖數量超過了這個層級的閾值時,就會進行鎖升級
  • 鎖升級就是用更大粒度的鎖替代多個更小粒度的鎖
  • 好比 InnoDB 中行鎖升級爲表鎖,這樣作的好處是佔用的鎖空間下降了,但同時數據的併發度也降低

2、數據庫管理的角度對鎖進行劃分

共享鎖
  • 讀鎖或 S 鎖,共享鎖鎖定的資源能夠被其餘用戶讀取,但不能修改
  • 在進行SELECT的時候,會將對象進行共享鎖鎖定
  • 當數據讀取完畢以後,就會釋放共享鎖,保證數據在讀取時不被修改
  • 數據表加上共享鎖的時候,該數據表就變成了只讀模式
  • 表共享鎖:LOCK TABLE 表名 READ;
  • 行共享鎖:select語句後面 接上LOCK IN SHARE MODE
  • 解鎖:UNLOCK TABLE;
排它鎖
  • 獨佔鎖、寫鎖或 X 鎖,排它鎖鎖定的數據只容許進行鎖定操做的事務使用
  • 其餘事務沒法對已鎖定的數據進行查詢或修改
  • 表排它鎖:LOCK TABLE 表名 WRITE;
  • 行排他鎖:select語句後面 接上FOR UPDATE
  • 解鎖:UNLOCK TABLE;
意向鎖
  • 給更大一級別的空間示意裏面是否已經上過鎖
  • 給某一行數據加上了排它鎖,數據庫會自動給更大一級的空間
  • 好比數據頁或數據表加上意向鎖,告訴其餘人這個數據頁或數據表已經有人上過排它鎖了
  • 當其餘人想要獲取數據表排它鎖的時候,只須要了解是否有人已經獲取了這個數據表的意向排他鎖便可
  • 好比加了一把行鎖
  • 數據庫在表或者頁上添加意向鎖
  • 當有其餘操做須要添加表鎖或者頁鎖時
  • 直接看到意向標示,就不一樣整表或者整頁掃描
  • 來判斷能不能上鎖

 

3、共享鎖會發生死鎖

  • 當有多個事務對同一數據得到讀鎖的時候,可能會出現死鎖的狀況
  • 相互等待相互不釋放手上資源

4、程序員的角度對進行劃分

樂觀鎖
  • 認爲對同一數據的併發操做不會總髮生,屬於小几率事件,不用每次都對數據上鎖,也就是不採用數據庫自身的鎖機制
  • 經過程序來實現
  • 能夠採用版本號機制或者時間戳機制實現
  • 版本號:UPDATE ... SET version=version+1 WHERE version=version
悲觀鎖
  • 一種思想,對數據被其餘事務的修改持保守態度,
  • 經過數據庫自身的鎖機制來實現,從而保證數據操做的排它性

 

  • 樂觀鎖適合讀操做多的場景,相對來講寫的操做比較少。它的優勢在於程序實現,不存在死鎖問題,不過適用場景也會相對樂觀,由於它阻止不了除了程序之外的數據庫操做
  • 悲觀鎖適合寫操做多的場景,由於寫的操做具備排它性。採用悲觀鎖的方式,能夠在數據庫層面阻止其餘事務對該數據的操做權限,防止讀 - 寫和寫 - 寫的衝突。

5、MVCC

全稱是 Multiversion Concurrency Control,中文翻譯過來就是多版本併發控制技術。從名字中也能看出來,MVCC 是經過數據行的多個版本管理來實現數據庫的併發控制,簡單來講它的思想就是保存數據的歷史版本。這樣咱們就能夠經過比較版本號決定數據是否顯示出來(具體的規則後面會介紹到),讀取數據的時候不須要加鎖也能夠保證事務的隔離效果數據庫

快照讀讀取的是快照數據,不加鎖的簡單的 SELECT 都屬於快照讀併發

  • 讀寫之間阻塞的問題,經過 MVCC 可讓讀寫互相不阻塞,即讀不阻塞寫,寫不阻塞讀,提高事務併發處理能力
  • 下降了死鎖的機率。MVCC 採用了樂觀鎖的方式,讀取數據時並不須要加鎖,對於寫操做,也只鎖定必要的行
  • 解決一致性讀的問題。一致性讀也被稱爲快照讀,當查詢數據庫在某個時間點的快照時,只能看到這個時間點以前事務提交更新的結果,而不能看到這個時間點以後事務提交的更新結果

InnoDB 中的 MVCC 實現

InnoDB 是如何存儲記錄的多個版本的。多版本對應 MVCC 前兩個字母的釋義:Multi Versionspa

事務版本號
  • 每開啓一個事務,咱們都會從數據庫中得到一個事務 ID(事務版本號)
  • 事務 ID 是自增加的,經過 ID 大小,咱們就能夠判斷事務的時間順序
 
行記錄的隱藏列
  • InnoDB 的葉子段存儲了數據頁
  • 數據頁中保存了行記錄,而在行記錄中有一些重要的隱藏字段
db_row_id 隱藏的行 ID
  • 用來生成默認彙集索引
  • 若是建立數據表的時候沒有指定彙集索引
  • nnoDB 就會用這個隱藏 ID 來建立彙集索引
  • 採用彙集索引的方式能夠提高數據的查找效率
db_trx_id 操做這個數據的事務 ID
  • 最後一個對該數據進行插入或更新的事務 ID
db_roll_ptr db_roll_ptr
  • 指向這個記錄的 Undo Log 信息

Undo Log
  • InnoDB 將行記錄快照保存在了 Undo Log 裏,咱們能夠在回滾段中找到它們

  • 回滾指針將數據行的全部快照記錄都經過鏈表的結構串聯了起來
  • 每一個快照的記錄都保存了當時的 db_trx_id,那個時間點操做這個數據的事務 ID
  • 若是咱們想要找歷史快照,就能夠經過遍歷回滾指針的方式進行查找

Read View 如何工做

  • 多個事務對同一個行記錄進行更新會產生多個歷史快照
  • 歷史快照保存在 Undo Log 裏
  • 若是一個事務想要查詢這個行記錄,須要讀取哪一個版本的行記錄?
  • 須要用到 Read View 它幫咱們解決了行的可見性問題
  • Read View 保存了當前事務開啓時全部活躍(尚未提交)的事務列表
  • 換個角度你能夠理解爲 Read View 保存了不該該讓這個事務看到的其餘的事務 ID 列表
trx_ids 系統當前正在活躍的事務 ID 集合
low_limit_id 活躍的事務中最大的事務 ID
up_limit_id 活躍的事務中最小的事務 ID
creator_trx_id 建立這個 Read View 的事務 ID

trx_ids 爲 trx二、trx三、trx5 和 trx8 的集合,活躍的最大事務 ID(low_limit_id)爲 trx8,活躍的最小事務 ID(up_limit_id)爲 trx2翻譯

  1. 當前有事務 creator_trx_id 想要讀取某個行記錄,這個行記錄的事務 ID 爲 trx_id,那麼會出現如下幾種狀況
  2. 若是 trx_id < 活躍的最小事務 ID(up_limit_id),也就是說這個行記錄在這些活躍的事務建立以前就已經提交了,那麼這個行記錄對該事務是可見的
  3. 若是 trx_id > 活躍的最大事務 ID(low_limit_id),這說明該行記錄在這些活躍的事務建立以後才建立,那麼這個行記錄對當前事務不可見
  4. 若是 up_limit_id < trx_id < low_limit_id,說明該行記錄所在的事務 trx_id 在目前 creator_trx_id 這個事務建立的時候,可能還處於活躍的狀態
  5. 所以須要在 trx_ids 集合中進行遍歷,若是 trx_id 存在於 trx_ids 集合中,證實這個事務 trx_id 還處於活躍狀態,不可見
  6. 不然,若是 trx_id 不存在於 trx_ids 集合中,證實事務 trx_id 已經提交了,該行記錄可見

當查詢一條記錄的時候,系統如何經過多版本併發控制技術找到它指針

  1. 首先獲取事務本身的版本號,也就是事務 ID
  2. 獲取 Read View
  3. 查詢獲得的數據,而後與 Read View 中的事務版本號進行比較
  4. 若是不符合 ReadView 規則,就須要從 Undo Log 中獲取歷史快照
  5. 最後返回符合規則的數據
  • InnoDB 中,MVCC 是經過 Undo Log + Read View 進行數據讀取,Undo Log 保存了歷史快照,而 Read View 規則幫咱們判斷當前版本的數據是否可見
  1. 在隔離級別爲讀已提交(Read Commit)時,一個事務中的每一次 SELECT 查詢都會獲取一次 Read View
  2. 當隔離級別爲可重複讀的時候,就避免了不可重複讀,這是由於一個事務只在第一次 SELECT 的時候會獲取一次 Read View,然後面全部的 SELECT 都會複用這個 Read View

InnoDB 如何解決幻讀

記錄鎖
  • 針對單個行記錄添加鎖
間隙鎖(Gap Locking)
  • 能夠幫咱們鎖住一個範圍(索引之間的空隙)
  • 不包括記錄自己
  • 採用間隙鎖的方式能夠防止幻讀狀況的產生
Next-Key 鎖
  • 鎖住一個範圍,同時鎖定記錄自己,至關於間隙鎖 + 記錄鎖
  • 能夠解決幻讀的問題
相關文章
相關標籤/搜索