🍖MySQL鎖機制

引入

1.什麼是鎖

  • 鎖是計算機協調多個進程或線程併發訪問某一資源的機制,咱們稱之爲鎖機制

2.爲什麼要使用鎖機制

  • 由於在數據庫中,除了傳統的計算資源(如CPU、RAM、I/O等)的爭用之外,數據也是一種供須要用戶共享的資源python

  • 當併發事務同時訪問一個共享的資源時,有可能致使數據不一致、數據無效等問題mysql

  • 例如在上一篇介紹過的事務併發狀況下出現的讀現象: 髒讀、不可重複讀、幻讀等算法

  • 爲了解決這些方法, 主流的數據庫軟件都提供了鎖機制, 以及事務隔離級別的概念sql

  • 而鎖機制能夠將併發的數據訪問順序化, 以保證數據庫中數據的一致性和有效性數據庫

ps : 鎖衝突也是影響數據庫併發性能的一個重要因素, 對鎖對數據庫很是重要, 但也更加複雜安全

3.併發控制

  • 在計算機科學,特別是程序設計、操做系統、多處理機和數據庫等領域,併發控制(Concurrency control)是確保及時糾正由併發操做致使的錯誤的一種機制
  • 爲了更好的應對高併發, 封鎖、時間戳、樂觀併發控制(樂觀鎖)和悲觀併發控制(悲觀鎖)是併發控制主要採用的技術手段

二.鎖分類

  • 按照按鎖的粒度劃分 : 可分爲行級鎖、表級鎖、頁級鎖架構

  • 按照級別劃分 : 可分爲共享鎖、排他鎖、意向鎖、間隙鎖(Next-Key)併發

  • 按照使用方式分 : 可分爲樂觀鎖、悲觀鎖高併發

  • 按照加鎖方式分 : 可分爲自動鎖、顯式鎖性能

  • 按照操做劃分 : DDL鎖、DML鎖

  • 其餘 : 死鎖、MVCC

三.DDL鎖與DML鎖

  • DML鎖(data locks, 數據鎖),用於保護數據的完整性, 其中包括行級鎖(Row Locks (TX鎖))、表級鎖(table lock(TM鎖))

  • DDL鎖(dictionary locks,數據字典鎖), 用於保護數據庫對象的結構,如表、索引等的結構定義; 其中包排他DDL(Exclusive DDL lock)、共享DDL鎖(Share DDL lock),可中斷解析鎖(Breakable parse locks)

四.MySQL中的行級鎖、表級鎖、頁級鎖 (按粒度分)

在DBMS中, 能夠按照鎖的粒度把數據庫鎖分爲行級鎖(Innodb引擎默認使用)、表級鎖(Myisam引擎默認使用)和頁級鎖(BDB引擎默認使用)

1.行級鎖

  • 行級鎖定義

行級鎖是Mysql中鎖定粒度最細的一種鎖, 表示只針對當前操做的行進行加鎖; 行級鎖能大大減小數據庫操做的衝突; 其加鎖粒度最小, 但加鎖的開銷也最大; 行級鎖分爲共享鎖和排它鎖

  • 特色

開銷大, 加鎖慢; 會出現死鎖; 鎖定粒度最小, 發生鎖衝突的機率最低, 併發也最高

  • 支持引擎

Innodb 引擎

  • 語法
"共享鎖(s)" : select * from [表名] where [條件] lock in share mode;
"排它鎖(x)" : select * from [表名] where [條件] for update;

2.表級鎖 (偏向於讀)

  • 表級鎖定義

表級鎖是MySQL中鎖定粒度最大的一種鎖, 表示對當前操做的整張表加鎖, 它實現簡單, 資源消耗較少, 被大部分MySQL引擎支持; 最常使用的Myisam與Innodb都支持表級鎖定; 表級鎖定分爲表共享讀鎖(共享鎖)和表獨佔寫鎖(排它鎖)

  • 特色

開銷小, 加鎖快; 不會出現死鎖; 鎖定粒度大, 發出鎖衝突的機率最高, 併發度最低

  • 支持引擎

Myisam引擎、Memory引擎、Innodb引擎

  • 示例
"語法" : lock table [表名1] [resd|write],[表名2] [resd|write], ...;   # 能夠加讀鎖或者寫做
lock table user read;  # 將表 user 加上寫鎖
show open tables where in_user>=1;       # 查看當前會話鎖定一次以上的表
update user set name="song" where id=1;  # 更新表數據(會提示表被鎖定)
unlock tables;  # 釋放當前會話持有的任何鎖
update user set name="song" where id=1;  # 再次更新能夠成功

image-20210228150932400

3.頁級鎖

  • 頁級鎖定義

頁級鎖是MySQL中鎖定粒度介於行級鎖和表級鎖中間的一種鎖; 表級鎖速度快, 但衝突多, 行級衝突少, 但速度慢; 因此取了折衷的頁級, 一次鎖定相鄰的一組記錄; BDB支持頁級鎖

  • 特色

開銷和加鎖時間界於表鎖和行鎖之間; 會出現死鎖; 鎖定粒度界於表鎖和行鎖之間, 併發度通常

  • 支持引擎

BDB引擎

五.Innodb中的行級鎖之共享鎖與排它鎖 (按級別分)

1.Innodb中行級鎖的與表鎖對比

  • InnoDB行鎖不是直接鎖記錄, 而是鎖索引, 這一點MySQL與Oracle不一樣, 後者是經過在數據塊中對相應數據行加鎖來實現的

  • InnoDB這種行鎖實現特色意味着:只有經過索引條件檢索數據, InnoDB才使用行級鎖, 不然,InnoDB將鎖住全部行, 實現的效果至關因而表鎖

  • 演示

create table t01(id int,name char(16));  # 建立表(而且不添加索引)
insert t01 value(1,"aa"),(2,"bb"),(3,"cc"),(4,"dd");  # 插入記錄
# 開啓兩個會話窗口, 分別手動開啓事務
# 事務1對 id=2 進行鎖行操做, 事務2對 id!=2 的行進行更新
# 發現阻塞, 一段時間後顯示超時 : ERROR 1205 (HY000): Lock wait timeout exceeded;....

image-20210228153157610

create index index_id on t01(id);  # 爲 id 字段建立索引
desc t01;  # 查看錶結構
# 再次重複上面開啓事務的步驟

image-20210228154050025

2.行鎖的實現原理

行鎖鎖的是索引, 索引又分爲主鍵索引和非主鍵索引兩種, 因此鎖定的方式分爲如下三種 :

  • 若是一條 sql 語句操做了主鍵索引, Mysql 就會鎖定這條語句命中的主鍵索引(或稱聚簇索引)
  • 若是一條語句操做了非主鍵索引(或稱輔助索引), MySQL會先鎖定該非主鍵索引, 再鎖定相關的主鍵索引
  • 若是沒有索引, InnoDB 會經過隱藏的聚簇索引來對記錄加鎖; 也就是說 : 若是不經過索引條件檢索數據, 那麼InnoDB將對錶中全部數據加鎖, 實際效果跟表級鎖同樣

3.實際應用中的問題

在實際應用中, 要特別注意InnoDB行鎖的這一特性, 不然可能致使大量的鎖衝突, 從而影響併發性能 :

  • 在不經過索引條件查詢的時候, InnoDB 行鎖鎖定全部行, 效果至關於表鎖
  • 當表有多個索引的時候, 不一樣的事務可使用不一樣的索引鎖定不一樣的行, 另外, 不論 是使用主鍵索引、惟一索引或普通索引, InnoDB 都會使用行鎖來對數據加鎖
  • 因爲 MySQL 的行鎖是針對索引加的鎖, 不是針對記錄加的鎖, 因此雖然是訪問不一樣行的記錄, 可是若是是使用相同的索引鍵, 也仍是會出現鎖衝突的
  • 即使在條件中使用了索引字段, 可是否使用索引來檢索數據是由 MySQL 經過判斷不一樣執行計劃的代價來決定的, 若是 MySQL 認爲全表掃 效率更高, 好比對一些很小的表, 它就不會使用索引, 這種狀況下 InnoDB 將鎖住全部的行, 至關於表鎖, 而不是行鎖; 所以, 在分析鎖衝突時, 別忘了檢查 SQL 的執行計劃, 以確認是否真正使用了索引

4.行級鎖分爲共享鎖和排他鎖

與對行處理有關的語句有 : insertupdatedeleteselect, 這四類語句在操做記錄時, 均可覺得行加上鎖, 但須要注意的是 :

  • 對於 insert、update、delete語句, InnoDB會自動給涉及的數據加鎖,並且是排他鎖 (簡稱X鎖)
# 手動開啓事務1,對 id=1 的記錄進行增刪改操做, 而且爲提交狀態
# 開啓事務2,也對 id=1 的記錄進行增刪改操做
# 發現阻塞在原地,一段時間後顯示超時 : ERROR 1205 (HY000): Lock wait timeout exceeded ....

image-20210228163926773

  • 對於普通的 select 語句, InnoDB不會加任何鎖, 須要咱們手動本身加, 能夠加兩種類型的鎖 :
"共享鎖(s)" : select * from [表名] where [條件] lock in share mode;
"排它鎖(x)" : select * from [表名] where [條件] for update;

5.共享鎖 (Share Lock)

  • 共享鎖定義

共享鎖又稱爲讀鎖, 簡稱S鎖, 顧名思義, 共享鎖就是多個事務對於同一數據能夠共享一把鎖, 獲准共享鎖的事務只能讀數據, 不能修改數據直到已釋放全部共享鎖, 因此共享鎖能夠支持併發讀

若是事務1對數據A加上共享鎖後, 則其餘事務只能對A再加共享鎖或不加鎖 (在其餘事務裏必定不能再加排他鎖, 可是在事務1本身裏面是能夠加的), 反之亦然

  • 共享鎖用法
select * from [表名] where [條件] lock in share mode;

在查詢語句後面增長lock in share mode,Mysql會對查詢結果中的每行都加共享鎖,當沒有其餘線程對查詢結果集中的任何一行使用排他鎖時, 能夠成功申請共享鎖, 不然會被阻塞; 其餘線程也能夠讀取使用了共享鎖的表, 並且這些線程讀取的是同一個版本的數據

6.排它鎖 (Exclusive Lock)

  • 排它鎖定義

排他鎖又稱爲寫鎖, 簡稱X鎖, 顧名思義, 排他鎖就是不能與其餘所並存, 如一個事務獲取了一個數據行的排他鎖, 其餘事務就不能再對該行加任何類型的其餘他鎖 (共享鎖和排他鎖), 可是獲取排他鎖的事務是能夠對數據就行讀取和修改

  • 排它鎖用法
select * from [表名] where [條件] for update;

在查詢語句後面增長for update, Mysql會對查詢結果中的每行都加排他鎖, 當沒有其餘線程對查詢結果集中的任何一行使用排他鎖時, 能夠成功申請排他鎖, 不然會被阻塞

加過排他鎖的數據行在其餘事務種是不能修改數據的, 也不能經過for updatelock in share mode鎖的方式查詢數據, 但能夠直接經過select ...from...查詢數據, 由於普通select查詢沒有任何鎖機制

7.共享鎖與排它鎖實驗

創建了索引且命中的狀況下:

  • 事務1對某記錄加排它鎖, 事務2沒法對該記錄進行"改"(三種操做)操做(上面已經演示過了)
  • 事務1對某記錄加共享鎖, 本身可讀可寫, 其餘事務只能讀不能寫

image-20210228170050117

  • 當其餘事務也加上共享鎖時, 這時候全部的事務都只能進行讀操做

image-20210228171920885

8.意向鎖

  • 概念

意向鎖是表級鎖, 其設計目的主要是爲了在一個事務中揭示下一行將要被請求鎖的類型

  • 做用

當一個事務在須要獲取資源鎖定的時候, 若是遇到本身須要的資源已經被排他鎖佔用的時候, 該事務能夠須要鎖定行的表上面添加一個合適的意向鎖

若是本身須要一個共享鎖, 那麼就在表上面添加一個意向共享鎖; 而若是本身須要的是某行(或者某些行)上面添加一個排他鎖的話, 則先在表上面添加一個意向排他鎖

  • Innodb中的兩種意向鎖
  • 意向共享鎖(IS) : 事務打算給數據行共享鎖; 事務在給一個數據行加共享鎖前必須先取得該表的IS鎖
  • 意向排他鎖(IX) : 事務打算給數據行加排他鎖; 事務在給一個數據行加排他鎖前必須先取得該表的IX鎖

ps : 意向鎖是InnoDB自動加的,不須要用戶干預

9.哪一種狀況使用表鎖

絕大部分狀況使用行鎖, 但在個別特殊事務中, 也能夠考慮使用表鎖

  • 事務須要更新大部分數據, 表又較大

若使用默認的行鎖,不只該事務執行效率低(由於須要對較多行加鎖,加鎖是須要耗時的); 並且可能形成其餘事務長時間鎖等待和鎖衝突; 這種狀況下能夠考慮使用表鎖來提升該事務的執行速度

  • 事務涉及多個表, 較複雜, 極可能引發死鎖, 形成大量事務回滾

這種狀況也能夠考慮一次性鎖定事務涉及的表, 從而避免死鎖、減小數據庫因事務回滾帶來的開銷固然, 應用中這兩種事務不能太多, 不然, 就應該考慮使用Myisam

10.行鎖優化建議

經過檢查 InnoDB_row_lock 狀態變量來分析系統上的行鎖的爭奪狀況, 在着手根據狀態量來分析改善

show status like "innodb_row_lock%";  # 查看行鎖狀態
  • 儘量讓全部數據檢索都經過索引來完成, 從而避免無索引行鎖升級爲表鎖
  • 合理設計索引, 儘可能縮小鎖的範圍
  • 儘量減小檢索條件, 避免間隙鎖
  • 儘可能控制事務大小, 減小鎖定資源量和時間長度
  • 儘量低級別事務隔離, 詳見下一章節

六.MySQL經常使用存儲引擎的鎖機制

  • Myisam和Memory默認採用表級鎖(table-level locking)
  • BDB採用頁面鎖(page-level locking)或表級鎖,默認爲頁面鎖
  • Innodb支持行級鎖(row-level locking)和表級鎖, 默認爲行級鎖 (偏向於寫)

Innodb 四種鎖定模式的共存邏輯關係 :

共享鎖(S) 排他鎖(X) 意向共享鎖(IS) 意向排他鎖(Ⅸ)
共享鎖(S) 兼容 衝突 兼容 衝突
排他鎖(X) 衝突 衝突 衝突 衝突
意向共享鎖(IS) 兼容 衝突 兼容 兼容
意向排他鎖(Ⅸ) 衝突 衝突 兼容 兼容

若是一個事務請求的鎖模式與當前的鎖兼容,InnoDB就將請求的鎖授予該事務;反之,若是二者不兼容,該事務就要等待鎖釋放

七.三種行鎖算法

1.Innodb 有三種行鎖算法, 而且都屬於排它鎖

  • Record Lock : 單個行記錄上的鎖
  • Gap Lock : 間隙鎖, 鎖定一個範圍, 但不包括記錄自己; GAP鎖的目的, 是爲了防止同一事務的兩次當前讀, 出現幻讀的狀況
  • Next-Key Lock : 等於Record Lock結合Gap Lock, 也就說Next-Key Lock既鎖定記錄自己也鎖定一個範圍, 特別須要注意的是, InnoDB存儲引擎還會對輔助索引下一個鍵值加上gap lock

2.什麼是間隙鎖

  • 當咱們用範圍條件而不是相等條件檢索數據, 並請求共享或排他鎖時, InnoDB會給符合條件的已有數據記錄的索引項加鎖
  • 對於鍵值在條件範圍內但並不存在的記錄, 叫作"間隙 (GAP)", InnoDB也會對這個"間隙"加鎖, 這種鎖機制就是所謂的間隙鎖 (Next-Key鎖)

image-20210228181506693

  • 示例 : 假設 emp 表中的有100條數據, 當使用 select * from emp where id>=100 for update; 語句的時候, 它是一個範圍條件檢索, 而且命中了索引, InnoDB不只會對符合條件的emp_id值爲100的記錄加鎖, 也會對em_pid大於100 (這些記錄並不存在) 的"間隙"加鎖

ps : 對於行的查詢, Innodb採用的都是Next-Key Lock, 主要目的是解決幻讀的問題, 以知足相關隔離級別以及恢復和複製的須要

八.死鎖問題

MyISAM中是不會產生死鎖的,由於MyISAM老是一次性得到所需的所有鎖,要麼所有知足,要麼所有等待。而在InnoDB中,鎖是逐步得到的,就形成了死鎖的可能

1.死鎖問題一 ( 兩個會話, 兩條 SQL語句產生死鎖)

  • 準備工做
create index index_id on t01;  # 刪除以前的索引
alter table t01 modify id int primary ket;  # 將id字段設置成主鍵
create index index_id on t01(id);  # 建立彙集索引
create index index_name on t01(name);  # 建立輔助索引(非彙集索引)
desc t01;  # 查看錶結構

image-20210228192015132

  • 開始試驗

image-20210228194048769

image-20210228194354431

2.死鎖問題二 (兩個事務, 一條SQL語句引發的死鎖)

img

第二個死鎖問題,只有多個事務同時運行的狀況下才可能出現,但隱蔽性極強,雖然每一個Session都只有一條語句,仍舊會產生死鎖。要分析這個死鎖,首先必須用到本文前面提到的MySQL加鎖的規則。針對Session 1,從name索引出發,讀到的[hdc, 1],[hdc, 6]均知足條件,不只會加name索引上的記錄X鎖,並且會加聚簇索引上的記錄X鎖,加鎖順序爲先[1,hdc,100],後[6,hdc,10]。而Session 2,從pubtime索引出發,[10,6],[100,1]均知足過濾條件,一樣也會加聚簇索引上的記錄X鎖,加鎖順序爲[6,hdc,10],後[1,hdc,100]。發現沒有,跟Session 1的加鎖順序正好相反,若是兩個Session剛好都持有了第一把鎖,請求加第二把鎖,死鎖就發生了

3.死鎖總結

  • 死鎖問題涉及到的問題
  • 在MySQL中, 行級鎖並非直接鎖記錄, 而是鎖索引; 索引分爲主鍵索引和非主鍵索引兩種
  • 若是一條sql語句操做了主鍵索引, MySQL就會鎖定這條主鍵索引
  • 若是一條語句操做了非主鍵索引, MySQL會先鎖定該非主鍵索引, 再鎖定相關的主鍵索引
  • 在update、delete操做時, MySQL不只鎖定WHERE條件掃描過的全部索引記錄, 並且會鎖定相鄰的鍵值, 即所謂的next-key locking
  • 死鎖產生的本質原理
  • 死鎖的發生與否, 並不在於事務中有多少條SQL語句, 死鎖的關鍵在於 : 兩個(或以上)的Session加鎖的順序不一致
  • 而使用上面提到的, 分析MySQL每條SQL語句的加鎖規則, 分析出每條語句的加鎖順序
  • 而後檢查多個併發SQL間是否存在以相反的順序加鎖的狀況, 就能夠分析出各類潛在的死鎖狀況, 也能夠分析出線上死鎖發生的緣由

4.如何避免死鎖

發生死鎖後, InnoDB通常均可以檢測到, 並使一個事務釋放鎖回退, 另外一個獲取鎖完成事務, 上面實驗也證實了, 但也有多種方法能夠避免死鎖:

  • 若是不一樣程序會併發存取多個表, 儘可能約定以相同的順序訪問表, 能夠大大下降死鎖機會
  • 在同一個事務中, 儘量作到一次鎖定所須要的全部資源, 減小死鎖產生機率
  • 對於很是容易產生死鎖的業務部分, 能夠嘗試使用升級鎖定顆粒度, 經過表級鎖定來減小死鎖產生的機率
  • 在程序以批量方式處理數據的時候, 若是事先對數據排序, 保證每一個線程按固定的順序來處理記錄, 也能夠大大下降出現死鎖的可能

九.樂觀鎖與悲觀鎖

數據庫管理系統 (DBMS) 中的併發控制的任務是確保在多個事務同時存取數據庫中同一數據時不破壞事務的隔離性和統一性以及數據庫的統一性

樂觀併發控制 (樂觀鎖) 和悲觀併發控制 (悲觀鎖) 是併發控制主要採用的技術手段。

不管是悲觀鎖仍是樂觀鎖, 都是人們定義出來的概念, 能夠認爲是一種思想; 其實不只僅是關係型數據庫系統中有樂觀鎖和悲觀鎖的概念, 像memcache、hibernate、tair等都有相似的概念

針對於不一樣的業務場景, 應該選用不一樣的併發控制方式; 因此, 不要把樂觀併發控制和悲觀併發控制狹義的理解爲DBMS中的概念, 更不要把他們和數據中提供的鎖機制 (行鎖、表鎖、排他鎖、共享鎖) 混爲一談; 其實, 在DBMS中, 悲觀鎖正是利用數據庫自己提供的鎖機制來實現的

十.悲觀鎖

1.悲觀鎖介紹

悲觀的認爲操做數據庫就是修改數據, 爲了不數據庫中的數據同時被修改, 直接對該操做加鎖處理

當咱們要對一個數據庫中的一條數據進行修改的時候, 爲了不同時被其餘人修改, 最好的辦法就是直接對該數據進行加鎖以防止併發

這種藉助數據庫鎖機制在修改數據以前先鎖定, 再修改的方式被稱之爲悲觀併發控制 (又名「悲觀鎖」,Pessimistic Concurrency Control, 縮寫「PCC」)

  • 在關係數據庫管理系統裏,悲觀併發控制 (又名「悲觀鎖」,Pessimistic Concurrency Control,縮寫「PCC」) 是一種併發控制的方法

  • 它能夠阻止一個事務以影響其餘用戶的方式來修改數據; 若是一個事務執行的操做都某行數據應用了鎖,那只有當這個事務把鎖釋放, 其餘事務纔可以執行與該鎖衝突的操做

  • 悲觀併發控制主要用於數據爭用激烈的環境, 以及發生併發衝突時使用鎖保護數據的成本要低於回滾事務的成本的環境中

悲觀鎖, 正如其名, 它指的是對數據被外界 (包括本系統當前的其餘事務, 以及來自外部系統的事務處理) 修改持保守態度(悲觀), 所以, 在整個數據處理過程當中, 將數據處於鎖定狀態;

悲觀鎖的實現, 每每依靠數據庫提供的鎖機制 (也只有數據庫層提供的鎖機制才能真正保證數據訪問的排他性, 不然, 即便在本系統中實現了加鎖機制, 也沒法保證外部系統不會修改數據) , 如今互聯網高併發的架構中, 受到 fail-fast 思路的影響, 悲觀鎖已經很是少見了

2.悲觀鎖的工做流程

  • 在對任意記錄進行修改前, 先嚐試爲該記錄加上排他鎖 (exclusive locking)

  • 若是加鎖失敗, 說明該記錄正在被修改, 那麼當前查詢可能要等待或者拋出異常; 具體響應方式由開發者根據實際須要決定

  • 若是成功加鎖, 那麼就能夠對記錄作修改, 事務完成後就會解鎖了

  • 其間若是有其餘對該記錄作修改或加排他鎖的操做, 都會等待咱們解鎖或直接拋出異常

ps : 行鎖、表鎖、讀鎖、寫鎖都是在操做以前先上排他鎖

3.悲觀鎖總結

悲觀併發控制主要用於數據爭用激烈的環境, 以及發生併發衝突時使用鎖保護數據的成本要低於回滾事務的成本的環境中

  • 優勢

悲觀併發控制其實是「先取鎖再訪問」的保守策略, 爲數據處理的安全提供了保證

  • 缺點
  • 在效率方面, 處理加鎖的機制會讓數據庫產生額外的開銷, 還有增長產生死鎖的機會
  • 在只讀型事務處理中因爲不會產生衝突, 也不必使用鎖, 這樣作只能增長系統負載
  • 會下降了並行性, 一個事務若是鎖定了某行數據, 其餘事務就必須等待該事務處理完才能夠處理那行數

十一.樂觀鎖

1.樂觀鎖介紹

樂觀的認爲操做數據庫不會形成衝突, 只有在對數據進行更新的時候纔會進行校驗. 若是衝突就返回錯誤讓用戶決定如何去作

  • 在關係數據庫管理系統裏, 樂觀併發控制 (又名「樂觀鎖」, Optimistic Concurrency Control, 縮寫「OCC」) 是一種併發控制的方法
  • 它假設多用戶併發的事務在處理時不會彼此互相影響, 各事務可以在不產生鎖的狀況下處理各自影響的那部分數據
  • 在提交數據更新以前, 每一個事務會先檢查在該事務讀取數據後, 有沒有其餘事務又修改了該數據
  • 若是其餘事務有更新的話, 正在提交的事務會進行回滾; 樂觀事務控制最先是由孔祥重 (H.T.Kung) 教授提出

樂觀鎖 (Optimistic Locking) 相對悲觀鎖而言, 樂觀鎖假設認爲數據通常狀況下不會形成衝突, 因此在數據進行提交更新的時候, 纔會正式對數據的衝突與否進行檢測, 若是發現衝突了, 則讓返回用戶錯誤的信息, 讓用戶決定如何去作

相對於悲觀鎖, 在對數據庫進行處理的時候, 樂觀鎖並不會使用數據庫提供的鎖機制; 通常的實現樂觀鎖的方式就是記錄數據版本

數據版本 : 爲數據增長的一個版本標識, 當讀取數據時, 將版本標識的值一同讀出, 數據每更新一次, 同時對版本標識進行更新

當咱們提交更新的時候, 判斷數據庫表對應記錄的當前版本信息與第一次取出來的版本標識進行比對, 若是數據庫表當前版本號與第一次取出來的版本標識值相等, 則予以更新, 不然認爲是過時數據

2.樂觀鎖的兩種實現方式

  • 使用版本號實現

每一行數據多一個字段version, 每次更新數據對應版本號+1,
原理 : 讀出數據, 將版本號一同讀出, 以後更新, 版本號+1, 提交數據版本號大於數據庫當前版本號, 則予以更新, 不然認爲是過時數據, 從新讀取數據

  • 使用時間戳實現

每一行數據多一個字段 time
原理 : 讀出數據, 將時間戳一同讀出, 以後更新, 提交數據時間戳等於數據庫當前時間戳, 則予以更新, 不然認爲是過時數據, 從新讀取數據

3.樂觀鎖總結

樂觀併發控制相信事務之間的數據競爭(data race)的機率是比較小的, 所以儘量直接作下去, 直到提交的時候纔去鎖定, 因此不會產生任何鎖和死鎖

十二.悲觀鎖與樂觀鎖如何選擇

二者的區別於使用場景 :

  • 樂觀鎖 : 樂觀鎖並未真正加鎖, 效率高; 一旦鎖的粒度掌握很差, 更新失敗的機率就會比較高, 容易發生業務失敗
  • 悲觀鎖 : 悲觀鎖依賴數據庫鎖, 效率低; 更新失敗的機率比較低

隨着互聯網三高架構 (高併發、高性能、高可用) 的提出, 悲觀鎖已經愈來愈少的被使用到生產環境中了, 尤爲是併發量比較大的業務場景

相關文章
相關標籤/搜索