mysql锁

138 阅读3分钟
  • 按兼容性分为:共享锁,排它锁
  • 按粒度分:
    行锁:记录锁
    表锁:意向锁,自增锁
    间隙锁
    临键锁

记录锁

只锁住一行,或者说一条记录

等值查询--唯一索引
当条件语句where是等值条件=,且条件列是为主键列或唯一索引列时,会触发记录锁:
SELECT * FROM lock_example WHERE id = 1 FOR UPDATE
其中id 列为主键列或唯一索引列
id 为 1 的记录行会被锁住
在通过 主键索引与唯一索引对数据行进行UPDATE 操作时,也会对该行数据加记录锁:
UPDATE lock_example SET age = 50 WHERE id = 1

间隙锁

Innodb在可重复读隔离级别下为了解决幻读问题时引入的锁机制,它锁住的是相邻两行之间的间隙,b+树叶子节点的左右连接的指针。
比如有一列age,值为13,18,22,35,39,47,在(18,22)的开区间之间加锁就是间隙锁

范围查询--唯一索引
(和间隙锁没有对应关系)
假如lock_example表中只有101条记录,其id的值分别是1,2,...,100,101
Select * from lock_example where id > 100 for update
InnoDB 不仅会对符合条件的 id值为 101 的记录加锁,也会对 id大于101(这些记录并不存在)的“间隙”加锁

临键锁

记录锁和间隙锁的结合,在左开右闭的区间范围加锁。
还是上例,有一列age,值为13,18,22,35,39,47,在(18,22] 的左开右闭区间加锁就是间隙锁。

一般是多个临键锁组成的区间加锁。

等值查询--普通索引
搜索列是非唯一索引,既索引列的值含有重复元素:
SELECT * FROM lock_example WHERE age = 22 FOR UPDATE
其中age非唯一索引,会对 (18,22] 和 (22,35] 两个临键锁区间加锁,即(18,35]

可以这样理解:当是唯一索引时,每次相同的sql查询的必然是相同唯一的记录,中间不会被插入相同的行(只是索引列的值相同,不指其他列),所以不会出现幻读。但是非唯一索引时,可以插入相同的行,可以在B+树当前叶子节点后面再加一个节点,所以会对当前叶子节点的水平指针也加锁,也就是对后面的间隙加锁。

UPDATE lock_example SET name = Vladimir WHERE age = 22
其中age非唯一索引

在根据非唯一索引 对记录行进行 UPDATE \ FOR UPDATE \ LOCK IN SHARE MODE 操作时,InnoDB 会获取该记录行的临键锁 ,并同时获取该记录行下一个区间的间隙锁

间隙锁(gap lock)与临键锁(next-key lock)只在Repeatable-Read(RR可重复读)以上的级别生效,Read-Committed(RC已提交读)下会失效

只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁