引入
1.什么是鎖
- 鎖是計算機協調多個行程或執行緒并發訪問某一資源的機制,我們稱之為鎖機制
2.為何要使用鎖機制
-
因為在資料庫中,除了傳統的計算資源(如CPU、RAM、I/O等)的爭用以外,資料也是一種供需要用戶共享的資源
-
當并發事務同時訪問一個共享的資源時,有可能導致資料不一致、資料無效等問題
-
例如在上一篇介紹過的事務并發情況下出現的讀現象: 臟讀、不可重復讀、幻讀等
-
為了解決這些方法, 主流的資料庫軟體都提供了鎖機制, 以及事務隔離級別的概念
-
而鎖機制可以將并發的資料訪問順序化, 以保證資料庫中資料的一致性和有效性
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; # 再次更新可以成功

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;....

create index index_id on t01(id); # 為 id 欄位創建索引
desc t01; # 查看表結構
# 再次重復上面開啟事務的步驟

2.行鎖的實作原理
行鎖鎖的是索引, 索引又分為主鍵索引和非主鍵索引兩種, 所以鎖定的方式分為以下三種 :
- 如果一條 sql 陳述句操作了主鍵索引, Mysql 就會鎖定這條陳述句命中的主鍵索引(或稱聚簇索引)
- 如果一條陳述句操作了非主鍵索引(或稱輔助索引), MySQL會先鎖定該非主鍵索引, 再鎖定相關的主鍵索引
- 如果沒有索引, InnoDB 會通過隱藏的聚簇索引來對記錄加鎖; 也就是說 : 如果不通過索引條件檢索資料, 那么InnoDB將對表中所有資料加鎖, 實際效果跟表級鎖一樣
3.實際應用中的問題
在實際應用中, 要特別注意InnoDB行鎖的這一特性, 否則可能導致大量的鎖沖突, 從而影響并發性能 :
- 在不通過索引條件查詢的時候, InnoDB 行鎖鎖定所有行, 效果相當于表鎖
- 當表有多個索引的時候, 不同的事務可以使用不同的索引鎖定不同的行, 另外, 不論 是使用主鍵索引、唯一索引或普通索引, InnoDB 都會使用行鎖來對資料加鎖
- 由于 MySQL 的行鎖是針對索引加的鎖, 不是針對記錄加的鎖, 所以雖然是訪問不同行的記錄, 但是如果是使用相同的索引鍵, 也還是會出現鎖沖突的
- 即便在條件中使用了索引欄位, 但是否使用索引來檢索資料是由 MySQL 通過判斷不同執行計劃的代價來決定的, 如果 MySQL 認為全表掃 效率更高, 比如對一些很小的表, 它就不會使用索引, 這種情況下 InnoDB 將鎖住所有的行, 相當于表鎖, 而不是行鎖; 因此, 在分析鎖沖突時, 別忘了檢查 SQL 的執行計劃, 以確認是否真正使用了索引
4.行級鎖分為共享鎖和排他鎖
與對行處理有關的陳述句有 : insert、update、delete、select, 這四類陳述句在操作記錄時, 都可以為行加上鎖, 但需要注意的是 :
- 對于 insert、update、delete陳述句, InnoDB會自動給涉及的資料加鎖,而且是排他鎖 (簡稱X鎖)
# 手動開啟事務1,對 id=1 的記錄進行增刪改操作, 并且為提交狀態
# 開啟事務2,也對 id=1 的記錄進行增刪改操作
# 發現阻塞在原地,一段時間后顯示超時 : ERROR 1205 (HY000): Lock wait timeout exceeded ....

- 對于普通的 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 update和lock in share mode鎖的方式查詢資料, 但可以直接通過select ...from...查詢資料, 因為普通select查詢沒有任何鎖機制
7.共享鎖與排它鎖實驗
建立了索引且命中的情況下:
- 事務1對某記錄加排它鎖, 事務2無法對該記錄進行"改"(三種操作)操作(上面已經演示過了)
- 事務1對某記錄加共享鎖, 自己可讀可寫, 其他事務只能讀不能寫

- 當其他事務也加上共享鎖時, 這時候所有的事務都只能進行讀操作

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鎖)

- 示例 : 假設 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; # 查看表結構

- 開始試驗


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

第二個死鎖問題,只有多個事務同時運行的情況下才可能出現,但隱蔽性極強,雖然每個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)的概率是比較小的, 因此盡可能直接做下去, 直到提交的時候才去鎖定, 所以不會產生任何鎖和死鎖
十二.悲觀鎖與樂觀鎖如何選擇
兩者的區別于使用場景 :
- 樂觀鎖 : 樂觀鎖并未真正加鎖, 效率高; 一旦鎖的粒度掌握不好, 更新失敗的概率就會比較高, 容易發生業務失敗
- 悲觀鎖 : 悲觀鎖依賴資料庫鎖, 效率低; 更新失敗的概率比較低
隨著互聯網三高架構 (高并發、高性能、高可用) 的提出, 悲觀鎖已經越來越少的被使用到生產環境中了, 尤其是并發量比較大的業務場景
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/265318.html
標籤:其他
