锁的算法
innodb 3种行锁的算法:
1.Record Lock: 单个行记录上锁。
2.Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。
3.Net-Key Lock:Record Lock+Gap Lock,锁定一个范围,并且锁定记录本身。
例如,一个索引有10,11,13,20四个值,那么所有可能被Net-Key Lock的区间为:
(-inf,10]
(10,11]
(11,13]
(13,20]
(20,inf)
默认情况下(隔离级别为Repeatable read),innodb对行的查询都用到时Net-Key Lock算法:
当查询的列是唯一索引时,innodb会对Net-Key Lock进行优化,降级为Record Lock.
看一个例子:
先创建一张表,并插入3行数据
mysql> create table t(
-> a int primary key);
Query OK, 0 rows affected (0.08 sec)
mysql> insert into t select 1;
Query OK, 1 row affected (0.08 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into t select 2;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into t select 3;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
建立两个会话A和B:
时间 | 会话A | 会话B |
1 | begin; | |
2 | select * from t where a = 3 for update; +---+ | a | +---+ | 3 | +---+ 1 row in set (0.00 sec) | |
3 | begin; | |
4 | insert into t select 4;
commit; | |
5 | commit; Query OK, 0 rows affected (0.00 sec) |
会话A对a=3进行了X锁定,并且a是主键且唯一
因此锁定的只是a=3这个值,而不是(2,3)这个范围,
所以在会话B插入a=4时,并不会阻塞。
当查询的列是辅助索引时,
对于聚集索引(主键) ,加Record Lock
对于辅助索引 ,Next-Key-Locking,
并对下一个键值加上gap lock
看个例子:
mysql> create table z(
-> a int,
-> b int,
-> primary key(a),
-> key(b)
-> );
Query OK, 0 rows affected (0.05 sec)
mysql> insert into z select 1,1;
Query OK, 1 row affected (0.11 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into z select 3,1;
Query OK, 1 row affected (0.02 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into z select 5,3;
Query OK, 1 row affected (0.04 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into z select 7,6;
Query OK, 1 row affected (0.08 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> insert into z select 10,8;
Query OK, 1 row affected (0.08 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from z;
+----+------+
| a | b |
+----+------+
| 1 | 1 |
| 3 | 1 |
| 5 | 3 |
| 7 | 6 |
| 10 | 8 |
+----+------+
时间 | 会话A | 会话B |
1 | begin;
| |
2 | select * from z where b=3 for update;
#对辅助索引b进行查询,使用Next-Key-Locking对b=3进行加锁。有两个索引,所以分别加锁。 对于聚集索引 ,a=5加Record Lock 对于辅助索引 ,b=3加Next-Key-Locking,锁定范围【1,3】, 并对下一个键值加上gap lock,即范围为(3,6)的锁 | |
3 | begin; | |
mysql> insert into z select 9,1;
# b=1在【1,3】范围内,因此被阻塞 | ||
4 | mysql> insert into z select 23,2;
# b=2在【1,3】范围内,因此被阻塞 | |
5 | mysql> insert into z select 6,5;
# b=2在(3,6)范围内,因此被阻塞, | |
6 | mysql> insert into z select 6,7;
#b=7不在锁定范围,因此不会被阻塞 | |
7 | commit; | |
8 | commit; |