MySQL--事務與鎖

事務


定義

事務是數據庫管理系統(DBMS)執行過程中的一個邏輯單位,由一個有限的數據庫操作序列構成。(維基百科)

MySQL只有InnoDB存儲引擎支持事務

事務的開啓和關閉
數據庫默認是自動事務開啓的,執行任意的增刪改都會自動開啓事務。
也可以手動開啓事務:

-- 設定事務是否自動開啓
set session autocommit = on/off;
-- 手工方式開啓
begin / start transaction      
-- 結束事務:提交或回滾
commit / rollback

事務的四大特性(ACID)

原子性(Atomicity)

是指事務中對數據庫的一系列操作,要麼都是成功,要麼都是失敗。

在InnoDB裏面是通過undo log來實現的, 它記錄了數據修改之前的值 (邏輯日誌),一旦發生異常,就可以用undo log來實現回滾操作。

一致性(Consistency)

指的是數據庫的完整性約束沒有被破壞,事務執行的前後都是合法的數據狀態。

隔離性(Isolation)

隔離性是指在併發操作中,不同事務之間應該隔離開來,使每個併發中的事務不會相互干擾。

持久性(durability)

事務提交成功,事務中所有的數據操作都必須是永久性的,被持久化到數據庫中,即使提交事務後,數據庫馬上崩潰,在數據庫重啓時,也必須能保證通過某種機制恢復數據。

持久性是通過redo log和雙寫緩衝機制(double write buffer)保證的。

事務併發的問題

髒讀

事務裏面,一個事務查詢的數據,因爲其他事務修改了數據且並沒有提交,導致前後兩次讀取情況不一致。

重複讀

事務裏面,一個事務查詢的數據,因爲其他事務修改/刪除了數據並且提交了,導致前後兩次讀取情況不一致。

幻讀

事務裏面,一個事務查詢的數據,因爲其他事務插入了數據並且提交了,導致前後兩次讀取情況不一致。

image

事務的隔離級別

讀未提交 (Read Uncommitted)

一個事務可以讀取到其他事務未提交的數據,會出現髒讀。叫做RU,沒有解決任何的問題。

讀已提交 (Read Committed)

一個事務只能讀取到其他事務已提交的數據,不能讀取到其他事務未提交的數據,解決了髒讀的問題。

可重複讀 (Repeatable Read)

同一個事務裏面多次讀取同樣的數據結果是一樣的,對讀取的數據快照或者加鎖,解決了重複讀,但不能解決幻讀。

串行化 (Serializable)

所有的事務都是串行執行的,對數據的操作需要排隊,不存在事務的併發操作了,所以解決了所有的問題。
image

併發控制實現

LBCC

Lock Based Concurrency Control(基於鎖的併發控制):在讀取數據前,對其加鎖,阻止其他事務對數據進行修改。

MVCC

Multi Version Concurrency Control(多版本的併發控制):生成一個數據請求時間點的一致性數據快照(Snapshot),並用這個快照來提供一定級別(語句級或事務級)的一致性讀取。

核心思想:查詢當前事務之前提交的已存在的數據,即使後面被其他事務修改或者刪除了,當前事務查到的還是之前的數據。後面其他事務新增的數據,當前事務是看不到的。

InnoDB爲每行記錄都實現了三個隱藏字段

  • ROWID:6字節,行標識。(主鍵索引有介紹)
  • DB_TRX_ID:6字節,插入或更新行的最後一個事務的事務ID,自增的(創建版本號
  • DB_ROLL_PTR:7字節,回滾指針,數據被刪除或記錄爲舊數據的時候,記錄當前事務ID(刪除版本號
MVCC的版本控制

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-h6yKOGS8-1590046122654)(http://assets.processon.com/chart_image/5ebcf2d17d9c08156c3febd0.png)]
MVCC的查找規則:只能查找創建時間小於等於當前事務ID的數據,和刪除時間大於當前事務ID的行(或未刪除)。

  1. 事務1 初始化插入了兩條user數據,此時創建版本是當前事務ID,刪除版本爲空。
  2. 事務2 查詢出來兩條user數據。
  3. 事務3 插入一條新數據,新數據創建版本是3,刪除版本爲空
  4. 事務2 查詢user表,根據規則,只能查到創建版本小於1的兩條數據
  5. 事務4 刪除user表第二條數據,該數據刪除版本爲4
  6. 事務2 查詢user表,根據規則,刪除版本4大於事務id2,可以被查出來。可以顯示兩條數據
  7. 事務5 更新user表第一條數據,原數據刪除版本爲5,新增一條創建版本爲5的版本數據,刪除版本爲空
  8. 事務2 查詢user表,根據規則,創建版本5大於事務id2,不展示,刪除版本5大於當前事務版本2可展示,所以展示原來的兩條數據。

通過版本號的控制,無論其他事務是插入、修改、刪除,第一個事務查詢到的數據都沒有變化。

InnoDB鎖機制


表鎖、行鎖

表鎖(Table Lock)

  • 表級鎖一次會將整個表鎖定,顆粒度大。
  • 加鎖效率高:獲取鎖和釋放鎖的速度快。
  • 鎖衝突概率高,避免死鎖
  • 併發性能差

行鎖(Record Lock)

  • 記錄鎖,加鎖的是數據行,鎖顆粒度小
  • 加鎖效率略低,加鎖邏輯複雜
  • 鎖衝突概率小,會出現死鎖
  • 併發性能高

行鎖表鎖對比

鎖定粒度: 表鎖 > 行鎖
加鎖效率: 表鎖 > 行鎖
衝突概率: 表鎖 > 行鎖
併發性能: 表鎖 < 行鎖

行鎖:共享鎖、排他鎖

共享鎖(Shared Locks)

定義

共享鎖,又稱爲讀鎖,簡稱S鎖。
共享鎖就是多個事務可以共享一把鎖,都能訪問到數據,但是能讀不能修改。

加鎖

select * from user where id=1 LOCK IN SHARE MODE;

釋放鎖

事務結束

排他鎖(Exclusive Locks)

定義

排他鎖,又稱爲寫鎖,簡稱X鎖。
排他鎖不能與其他鎖並存,一個事務獲取數據行的排他鎖,其他事務就不能再獲取該數據的鎖(共享鎖、排他鎖),只有該獲取了排他鎖的事務可以對數據行進行讀取和修改。

加鎖

自動:delete / update / insert 默認加上X鎖;
手動:select * from student where id=1 FOR UPDATE;

釋放鎖

事務結束

InnoDB行鎖實現

核心:行鎖鎖的是索引
InnoDB行鎖是通過給索引上的索引項加鎖來實現的,只有通過索引條件檢索數據,才使用行級鎖;在不通過索引條件查詢的時候,將使用表鎖。

意向鎖(Intention Lock)(表級)

意向鎖是由數據引擎自己維護的,用戶無法手動操作意向鎖 。

意向共享鎖(Intention Shared Lock,簡稱IS鎖)

表示事務準備給數據行加入共享鎖,也就是說一個數據行加共享鎖前必須先取得該表的IS鎖。

意向排他鎖(Intention Exclusive Lock,簡稱IX鎖)

表示事務準備給數據行加入排他鎖,說明事務在一個數據行加排他鎖前必須先取得該表的IX鎖。

意向鎖作用

表級和行級鎖共存時,意向鎖相當於一個表flag。
當該表被事務A加了行鎖,事務B又準備加表鎖,應該是阻塞的。這時候如果遍歷所有行判斷是否有鎖,效率低。直接判斷是否有意向鎖就能給出結果,效率高。

行鎖算法

記錄鎖(Record Lock)

記錄(Record)

image
索引中存在的主鍵值,叫做Record。

單個行記錄上的鎖,通過索引使用等值查詢,精準匹配到一條記錄的時候,這個時候使用的就是記錄鎖。

例:

-- 鎖住id 爲2
select * from user where id = 2 for update;

間隙鎖(Gap Lock)

間隙(Gap)

image
存在的Record隔開的數據,不存在的區間,叫做間隙(Gap),是一個左開右開的區間

查詢的記錄不存在,沒有命中任何一個record,無論是用等值查詢還是範圍查詢的時候,此時使用的是間隙鎖。
不會阻塞相同的間隙鎖,但是會阻塞插入間隙鎖,這也是用來防止幻讀的關鍵
間隙鎖,只在RR隔離級別下存在。

例:

-- 返回查詢
select * from user where id >4 and id <7 for update;
-- 等值查詢沒命中
select * from user where id = 6 for update;

-- 阻塞插入 block
insert user id(5) 

鎖定了間隙區間,阻塞插入。

臨鍵鎖(Next-key Lock)

臨鍵(Next-key)

image
間隙(Gap)連同右邊的記錄(Record),我們把它叫做臨鍵的區間,是一個左開右閉的區間。

使用範圍查詢時,命中Record記錄,還包含Gap間隙,就使用臨鍵鎖
是MySQL裏面默認的行鎖算法,相當於記錄鎖加上間隙鎖。
臨鍵鎖,鎖住最後一個key的下一個左開右閉的區間。

例:

-- 鎖住(4,7]和(7,10]
select * from t2 where id >5 and id <=7 for update; 
-- 鎖住(7,10],(10,+∞)
select * from t2 where id >8 and id <=10 for update; 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章