寫在最前
這是讀書筆記,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鎖。