行级锁,每次操作锁住对应的行数据。锁定粒度最小,发生锁冲突的概率最低,并发度最高。
InnoDB的数据是基于索引组织的,行锁是通过对索引上的索引项加锁来实现的,而不是对记录加的锁。对于行级锁,主要分为以下三类:
- 行锁(Record Lock):锁定单个行记录的锁,防止其他事务对此行进行update和delete。在RC、RR隔离级别下都支持。

默认情况下,InnoDB在REPEATABLE READ事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。
- 针对唯一索引进行检索时,对已存在的记录进行等值匹配时,将会自动优化为行锁

在事务里使用select * from stu where id=1 lock in share mode;
会产生行锁和表的意向锁。

共享锁和共享锁兼容。
id为1的加了行锁之后,可以对id=3的进行更新操作
update stu set name='java' where id=3;

如果更新id=1的,就会处于阻塞状态。

- InnoDB的行锁是针对于索引加的锁,不通过索引条件检索数据,那么InnoDB将对表中的所有记录加锁,此时就会升级为表锁。
name字段没有索引的情况下,执行
begin;
update stu set name='php' where name='java';
在另外的事务中
begin;
update stu set name='spring' where name='tom'; 会被锁住,说明上面的执行升级为表锁了。

- 间隙锁(Gap Lock):锁定索引记录间隙(不含该记录),确保索引记录间隙不变,防止其他事务在这个间隙进行insert,产生幻读。在RR隔离级别下都支持。
默认情况下,InnoDB在REPEATABLE READ事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。
(1)索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。
在唯一索引上,更新一条不存在的记录
begin;
update stu set name='tomcat' where id=5;

这个时候,3和8之间(不包含3,8)就会被锁住GAP,
使用insert语句进行验证
begin;
insert into stu values(7, 'springboot', 7); 会一直堵塞在那里,直到左边的事务提交。

(2)索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,next-key lock退化为间隙锁。
先在age上创建普通索引(非唯一索引)
create index idx_age on stu(age);

(3)索引上的范围查询(唯一索引),会访问到不满足条件的第一个值为止。
- 临键锁(next-key Lock):行锁和间隙锁组合,同时锁住数据,并锁住数据前面的间隙Gap。在RR隔离级别下支持。
在并发访问时,解决数据访问的一致性、有效性问题。分全局锁、表级锁、行级锁。
全局锁是对整个数据库实例加锁,加锁后整个实例就处于只读状态,性能较差,数据逻辑备份时使用。
表级锁是操作锁住整张表,锁定粒度大,发生锁冲突的概率高,分为表锁、元数据锁,意向锁。
行级锁是操作锁住对应的行数据,锁定粒度最小,发生锁冲突的概率最低,分为行锁、间隙锁、临键锁。