數據庫本質上是一種共享資源
,所以在最大程度提供併發訪問性能的同時,仍須要確保每一個用戶能以一致的方式讀取和修改數據。鎖機制(Locking)
就是解決這類問題的最好武器。mysql
首先新建表 test
,其中 id
爲主鍵,name
爲輔助索引,address
爲惟一索引。程序員
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` int(11) NOT NULL,
`address` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idex_unique` (`address`),
KEY `idx_index` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
複製代碼
可見,若是兩個事務前後對主鍵相同的行記錄執行 INSERT
操做,由於事務 A
先拿到了行鎖,事務 B
只能等待直到事務 A
提交後行鎖被釋放。同理,若是針對惟一索引字段 address
進行插入操做,也須要獲取行鎖,圖同主鍵插入過程相似,再也不重複。sql
可是,若是兩個事務都針對輔助索引字段 name 進行插入,不須要等待獲取鎖,由於輔助索引字段即便值相同,在數據庫中也是操做不一樣的記錄行,不會衝突。數據庫
Update
方法與 Insert
方法結果相似。bash
事務 A
SELECT FOR UPDATE
語句會拿到表 test
的 Table Lock
,此時事務 B
去執行插入操做會阻塞,直到事務 A
提交釋放表鎖後,事務 B
才能獲取對應的行鎖執行插入操做。併發
可是若是事務 A 的 SELECT FOR UPDATE 語句緊跟 WHERE id = 1 的話,那麼這條語句只會獲取行鎖,不會是表鎖,此時不阻塞事務 B 對於其餘主鍵的修改操做ide
先看下 test
表下的數據狀況:性能
mysql> select * from test;
+----+------+---------+
| id | name | address |
+----+------+---------+
| 3 | 1 | 3 |
| 6 | 1 | 2 |
| 7 | 2 | 4 |
| 8 | 10 | 5 |
+----+------+---------+
4 rows in set (0.00 sec)
複製代碼
間隙鎖能夠說是行鎖的一種,不一樣的是它鎖住的是一個範圍內的記錄,做用是避免幻讀,即區間數據條目的忽然增減。解決辦法主要是:ui
id = 7
的 name
字段爲 1
,那麼 name = 1
的條數就從 2
變爲 3
)InnoDB
自動使用間隙鎖的條件爲:spa
Repeatable Read
隔離級別,這是 MySQL
的默認工做級別當 InnoDB
掃描索引記錄的時候,會首先對選中的索引行記錄加上行鎖,再對索引記錄兩邊的間隙(向左掃描掃到第一個比給定參數小的值, 向右掃描掃描到第一個比給定參數大的值, 以此構建一個區間)加上間隙鎖。若是一個間隙被事務 A
加了鎖,事務 B
是不能在這個間隙插入記錄的。
咱們這裏所說的 「間隙鎖」 其實不是 GAP LOCK,而是 RECORD LOCK + GAP LOCK,InnoDB 中稱之爲 NEXT_KEY LOCK
下面看個例子,咱們建表時指定 name
列爲輔助索引,目前這列的取值有 [1,2,10]。間隙範圍有 (-∞, 1]、[1,1]、[1,2]、[2,10]、[10, +∞)
Round 1:
Round 2:
Round 3:
這是一個不定時更新的、披着程序員外衣的文青小號,歡迎關注。