本文主要是針對《Mysql技術內幕:InnoDB 存儲引擎》一書中第六章關於 InnoDB 存儲引擎中鎖的學習總結。mysql
鎖是數據庫系統區別於文件系統的一個關鍵特性,爲了支持對共享資源的併發訪問,提供數據的完整性和一致性,咱們必須爲數據加鎖,InnoDB 提供了一致性非鎖定讀、行級鎖的支持。算法
鎖類型 | S 鎖 | X 鎖 |
S 鎖 | 兼容 | 不兼容 |
X 鎖 | 兼容 | 不兼容 |
鎖類型 | IS 鎖 | IX 鎖 |
表 S 鎖 | 兼容 | 不兼容 |
表 X 鎖 | 兼容 | 不兼容 |
在數據庫的默認隔離級別爲 REPEATABLE READ 下,Select 查詢默認爲一致性非鎖定讀,若是想要使用一致性鎖定讀,須要顯示給 Select 查詢加鎖sql
Select ... FOR UPDATE - 給讀取的行加上 X 鎖
Select ... LOCK IN SHARE MODE - 給讀取的行加上 S 鎖
複製代碼
CREATE TABLE `test` (
`id` int(1) NOT NULL AUTO_INCREMENT,
`name` varchar(8) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12;
複製代碼
- 0:這是 MySQL5.1.22 版本以前自增加的實現方式,即經過表鎖的 AUTO-INC Locking 方式
- 1:這是該參數的默認值。對於 simple inserts 該值會用互斥量去對內存中的計數器進行累加的操做,
對於 bulk inserts 仍是使用傳統表鎖的 AUTO-INC Locking方式
- 2:在這個模式下,對於全部的 insert-like 自增加的產生都是經過互斥量,
而不是經過 AUTO-INC Locking 的方式,顯然這時性能最高的方式。
然而會帶來必定的問題。由於併發插入的存在,在每次插入時,自增加的值可能不是連續的。
複製代碼
- Record Lock(行鎖):單個行記錄上的鎖,鎖定單條索引記錄。
- Gap Lock(間隙鎖):鎖定一個範圍,但不包括記錄自己
- Next-Key Lock(臨鍵鎖):是行鎖和間隙鎖的結合,鎖定一個範圍,而且鎖定記錄自己。
複製代碼
- 此時全部在(1,10)區間內的記錄行都會被鎖住
SELECT * FROM table WHERE id BETWEN 1 AND 10 FOR UPDATE;
複製代碼
- 執行如下 SQL 時,InnoDB 會獲取 24 對應的臨鍵鎖 (10, 24],並獲取下一個區間的間隙鎖 (24, 32),因此最終在 (10, 32) 區間加上間隙鎖
SELECT * FROM table WHERE age = 24 FOR UPDATE;
- 以後若是在其它事務中執行如下命令,則該命令會被阻塞:
INSERT INTO table(age, name) VALUES(26, 'Ezreal');
複製代碼
方式一:將事務的隔離級別設置成 READ COMMITTED
方式二:將參數 innodb_locks_unsafe_for_binlog 設置爲 1
複製代碼
- 髒讀是指在併發狀況下,當前事務能夠讀到其它事務未提交到數據
- 髒讀違反了數據庫事務的隔離性要求
- InnoDB 中髒讀的發生條件是事務的隔離級別爲 READ UNCOMMITED
複製代碼
- 不可重複讀是指同一個事務內,屢次讀取同一個數據集合結果不一致現象
- 不可重複讀違反了數據庫事務的一致性要求
- InnoDB 經過 next-key 算法來避免不可重複讀現象
- 爲了不不可重複讀現象發生,須要將事務的隔離級別設置爲 REPEATABLE READ 以上
複製代碼
- 丟失更新是指一個事務的更新操做會被令一個事務的更新操做覆蓋
- 在當前數據庫任何隔離級別下,都不會致使數據庫丟失更新現象發生
複製代碼
- 阻塞主要是爲了確保事務的併發可以正常有序的執行
- 經過參數 innodb_lock_wait_timeout 來設置事務的超時等待時間,默認是 50 s
- 經過參數 innodb_rollback_on_timeout 來設置事務超時是否進行回滾,默認不進行回滾
- 超時狀況下默認不進行回滾,須要業務來捕獲超時異常主動進行回滾,不然會致使數據的不一致性發生
複製代碼
innoDB 解決死鎖的兩種方案:
- 事務超時回滾事務,這種方案的缺點是若是超時的事務佔用的比重比較大,回滾很是耗時
- 採用 wait-for graphic(等待圖) 來進行死鎖檢查,經過深度優先遍歷算法主動檢查死鎖發生,釋放回滾 undo 量最小的事務
複製代碼