mysql-innodb-鎖

寫在最前

這是讀書筆記,Mysql,innodb系列一共3篇。算法

鎖基本概念

鎖類型 說明 鎖級別
意向共享鎖 IS Lock 事務想要得到一張表中某幾行的數據的共享鎖 表級別鎖
意向排他鎖IX Lock 事務想要得到一張表中某幾行數據的排他鎖 表級別鎖
共享鎖S Lock 容許事務讀取一行數據 行級別鎖
排他鎖X Lock 容許事務更新或刪除一條數據 行級別鎖

加鎖方式

記錄r進行上X鎖,先對數據庫A、表、頁上加意向鎖IX,才能對記錄r上X鎖。

兼容性


IS IX S X
IS 兼容 兼容 兼容 不兼容
IX 兼容 兼容 不兼容 不兼容
S 兼容 不兼容 兼容 不兼容
X 不兼容 不兼容 不兼容 不兼容

鎖的監控表

查詢鎖的狀況:information_schema下
  • innodb_trx事務表
  • innodb_locks鎖表
  • innodb_lock_wait鎖等待表

鎖算法

3種鎖算法

Record Lock
單行記錄加鎖
Gap Lock
Gap Lock間隙鎖,鎖一個範圍
阻止多個事務將記錄插入到同一範圍內
Next Key Lock
Next Key Lock:Record Lock+Gap Lock,鎖一個範圍+鎖一個記錄
查詢的列是惟一索引的狀況時,降級爲Record Lock。

舉例說明

建表插入數據
CREATE TABLE z(
a INT,
b INT,
PRIMARY KEY(a),
index index_b(b)
);
INSERT INTO z SELECT 1,1;
INSERT INTO z SELECT 3,1;
INSERT INTO z SELECT 5,3;
INSERT INTO z SELECT 7,6;
INSERT INTO z SELECT 10,8;複製代碼
會話A
begin;SELECT*FROM z WHERE b=3 FOR UPDATE;複製代碼
會話B
begin;SELECT*FROM z WHERE a=5 LOCK IN SHARE MODE;複製代碼
不能執行Record Lock 鎖定了5

2. INSERT INTO z SELECT 4,2;    複製代碼

不能執行有Gap Lock

非一致性鎖定讀/一致性鎖定讀

非一致性鎖定讀

1. 不須要等待訪問的行上X鎖的釋放,直接讀快照,提升了數據庫的併發性。
2. 快照數據來自undo段。undo段會用在事務回滾,因此快照數據自己沒有額外開銷。
3. 讀快照信息不須要上鎖,沒有事務須要處理歷史數據。

READ COMMITTED和 REPEATABLE READ快照定義的區別

隔離級別 讀取的快照數據 是否默認
隔離級別
存在的問題
READ COMMITTED 讀鎖定行最新的一份提交過數據 會出現幻讀
REPEATABLE READ 讀鎖定行事務開始前的版本

一致性鎖定讀

鎖定讀的語句 加鎖類型 注意事項
select ... for update 加X鎖 務必加上BEGIN,
START TRANSACTION或者
SET AUTOCOMMIT=0
select ... lock in share mode 加S鎖

鎖常見問題

髒讀,違反隔離性Isolation

不一樣的事務下,當前事務能夠讀到另外事務未提交的數據。
read uncommitted隔離級別下會發生

不可重複(Phantom Problem幻讀)

一個事務內兩次讀到的數據是不同的狀況(當前事務沒有結束。另一個事務修改了)。
READ COMMITTED下會發生,會讀到已經提交的數據 。
默認的事務隔離級別是
REPEATABLE READ。採用Next-Key Locking的算法,解決。
鎖一個範圍+鎖一個記錄。

丟失更新

任何隔離級別下都不會發生,可是應用層面會發生.
//假設id=3的帳號餘額爲100,A事務轉帳99,
Update t set a=1 where id=3
//B事務轉帳1
Update t set a=99 where id=3
//B事務後提交,最後餘額是99,A事務的丟失了複製代碼
解決方式:
串行化處理,樂觀鎖等

阻塞

一個事務中的鎖須要等待另外一個事務中的鎖釋放它所佔用的資源
innodb_lock_wait_timeout來控制等待時間默認50s
innodb_rollback_on_timeout設置超時時是否回滾,默認off,不回滾。

死鎖

兩個事務,爭奪鎖,相互等待。
死鎖發生的機率通常很低
  • 系統中事務的數量(n),數量越多發生死鎖的機率越大
  • 每一個事務操做的數量(r),每一個事務操做的數量越多,發生死鎖的機率越大
  • 操做數據的集合(R),越小則發生死鎖的機率越大
解決方式:
設置超時,等待超時的回滾,沒有超時的繼續,可是併發降低
innodb_lock_wait_timeout來控制等待時間默認50s
一般來講InnoDB存儲引擎選擇回滾undo量最小的事務

補充2-自增加與鎖

自增加的列,必須是索引,且必須是索引的第一個列。
AUTO-INC Locking:
當對含有自增加的計數器的表進行插入操做時,這個計數器會被初始化。
執行: SELECT MAX(auto_inc_col)FROM t FOR UPDATE;
插入操做會依據這個自增加的計數器值加1賦予自增加列
該鎖在執行完插入自增加值的SQL後釋放
提升了部分性能,可是對應insert select會受影響,須要等待另一個事務的完成AUTO-INC Locking。
Mysql5.1.22後,提供了輕量級互斥量,在內存中計算自增值提升性能

補充3-外鍵與鎖

innodb外鍵自動加索引
插入或更新數據時,
先使用SELECT…LOCK IN SHARE MODE方式,即主動對父表加一個S鎖。
相關文章
相關標籤/搜索