参考资料

MySQL (4) | 五分钟搞清楚InnoDB锁机制
MySQL 的锁机制 - 共享/排它锁
MySQL的锁机制 - 记录锁、间隙锁、临键锁

Innodb锁类型

  • 共享锁(S,行锁):可以与其他事务共享,对于同一数据共享一把锁,都能访问数据,但只读(加锁方式:select * from users where id = 1 lock in share mode)
  • 排他锁(X,行锁):排他锁不能与其他事务共享数据,同一时间内只允许一个事务对同一数据加一个排他锁,其他数据无法获得该数据的任何锁(加锁方式:select * from users where id = 1 for update)
  • 意向共享锁(IS,表锁):在给某些数据加共享锁之前,mysql会自动给此数据所在的表加意向共享锁(无需人为干预)
  • 意向排他锁(IX,表锁):在给某些数据加排他锁之前,mysql会自动给此数据所在的表加意向排他锁(无需人为干预)

意向锁的意义:当事务想去进行锁表时,可以先判断意向锁是否存在,存在时则可快速的返回,告知该表不能启用表锁(也就是会锁住对应会话),提高了加锁的效率。
**

Innodb行锁算法

(粒度由大到小)

  • 邻键锁(Next-Key Lock)
  • 间隙锁(Gap Lock)
  • 记录锁(Record Lock)

首先,行锁锁的是索引上的索引项,所以InnoDB只有在使用索引检索数据的时候+的是行锁,否则都是表锁

邻键锁(Next-Key Lock)

当sql执行按照索引进行范围查询时(>,<,between等),并有数据命中,则sql语句会加上Next-Key Lock,锁住索引的记录区间加下一个记录区间,这个区间是左开右闭的。

如图,我们假设一张表中的数据行的id为1,4,7,10
image.png
则Innodb会把这个表的数据划分成如图五个区间,当我们执行图中的SQL语句时,会发现,图中的(4,7],(7,10]两个区间被锁住了

间隙锁(Gap Lock)

在前图的的检索条件下,如果在主键5~9内无记录存在,Next-Key Lock会退化成Gap Lock,锁住数据不存在的区间(左开右开)
image.png

记录锁(Record Lock)

当SQL执行按照唯一性索引(Primary Key, Unique Key)检索数据时,查询条件等值匹配切查询的数据存在,这时SQL语句上加的锁即为Record Lock,锁住具体的索引项
image.png

总结

  • 加 X 锁 避免了数据的脏读(“我在写数据呢,别来凑热闹,不准读不准读!”)

  • 加 S 锁 避免了数据的不可重复读(“我在读数据呢,别想改我要读的数据!”)

  • 加上 Next Key 避免了数据的幻读(“我再读数据呢,别想往我读数据的区间里插入新数据!”)