行锁的3种算法
锁是针对索引加锁,如果查询条件无索引,全表扫描、全表锁。不讨论!
1.Record LOCK 单行记录上的锁
2.Gap LOCK 间隙锁,锁定一个范围,但不包含记录本身
3.Next-KEY Lock:Gap LOCK+Record Lock,锁定一个范围,并且锁定记录本身
Innodb对于行的查询都是采用Next-KEY Lock,但是当查询索引时含有唯一索引时,Innodb会对Next-KEY lock进行优化,降级为Record LOCK。仅锁住索引本身而非范围。
创建表
CREATE TABLE `t_student` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(128) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name` (`name`)
) ;
普通索引
数据库空表无记录
步骤 | sessionA | sessionB |
1 | begin; |
|
2 |
| begin; |
3 | select * from t_student where name='xm' for update; |
|
4 |
| insert into t_student(name) values ('xm'); -- 锁等待 |
5 | commit; | insert成功 |
|
|
|
分析:
Next-KEY Lock 锁定范围包含记录本身,因为此时数据无记录
锁定范围(-∞,+∞),
即为全表锁。
数据库表有一条记录
步骤 | sessionA | sessionB |
1 | begin; |
|
2 |
| begin; |
3 | select * from t_student where name='xm' for update; |
|
4 |
| insert into t_student(name) values ('xm2'); -- 锁等待 |
5 | commit; | insert成功 |
|
|
|
分析
select * from t_student where name='xm' for update;
锁定范围
(-∞,’xm’)
[‘xm’,+∞)
还是全表锁
步骤 | sessionA | sessionB |
1 | begin; |
|
2 |
| begin; |
3 | select * from t_student where name='xm5' for update; |
|
4 |
| insert into t_student(name) values ('xm8'); -- 不等待 |
5 | commit; | insert成功 |
|
|
|
分析
select * from t_student where name='xm5' for update;
锁定范围
(-∞,’xm5’)
所以插入 name=’xm8’ 无需等待锁
数据库表有2条记录
步骤 | sessionA | sessionB |
1 | begin; |
|
2 |
| begin; |
3 | select * from t_student where name='xm6' for update; |
|
4 |
| insert into t_student(name) values ('xm7'); -- 锁等待 |
5 | commit; | insert成功 |
|
|
|
分析
select * from t_student where name='xm6' for update;
锁定范围
(‘xm’,’xm6’)
[‘xm6’,+∞)
所以插入name=’xm999’ 需等待锁
步骤 | sessionA | sessionB |
1 | begin; |
|
2 |
| begin; |
3 | select * from t_student where name='xm6' for update; |
|
4 |
| insert into t_student(name) values ('aaa'); -- 不等待锁 |
|
|
|
|
|
|
分析
select * from t_student where name='xm6' for update;
锁定范围
(‘xm’,’xm6’)
name=‘aaa’不在锁的范围,所以不冲突。
唯一索引
数据库空表无记录
步骤 | sessionA | sessionB |
1 | begin; |
|
2 |
| begin; |
3 | select * from t_student where name='xm' for update; |
|
4 |
| insert into t_student(name) values ('xm6'); -- 锁等待 |
5 | commit; | insert成功 |
|
|
|
分析
表无记录时,锁定全表,InnoDB引擎不知道你将会在哪个范围插入数据
全表锁
数据库有1条记录
分析
查询索引时含有唯一索引时,Innodb会对Next-KEY lock进行优化,降级为Record LOCK。仅锁住索引本身而非范围