宽泛地谈谈 Mysql 锁

gomkiri 发布于 2025-10-29 80 次阅读


AI 摘要

MySQL锁如何解决幻读?共享锁与排他锁有何区别?意向锁如何避免全表扫描?记录锁、间隙锁、临键锁分别锁定什么范围?分布式系统为何要放弃自增主键?一文读懂MySQL锁机制的核心要点。

在谈 Mysql 事务的时候,提到在可重复读级别下不仅可以解决当前读级别下的幻读问题,还能解决当前读级别下的幻读问题,而解决方案就是使用 Mysql 锁。

要谈 Mysql 锁,需要从两个方向来看,分别是锁的模式和锁的算法,锁的模式可以分为共享锁、排他锁和意向锁。锁的算法也可以称为锁的粒度,可以有记录锁、间隙锁和意向锁等等。

锁模式

  1. 共享锁(Shared Locks
    这是一种读锁,读读之间不互斥,读写之间互斥
    SELECT 语句在可重复读级别下和串行化级别下会自动为其加上 S 锁
    除了自动加锁,我们也可以在 Select 语句执行时手动加锁,但是这种做法是不被推荐的,因为有很大的可能会造成死锁,加锁语句:SELECT … LOCK IN SHARE MODE
  2. 排他锁(Exclusive Locks,又称为 X 锁
    这是一种写锁,跟其他读、写操作都是相互互斥的
    在更新、删除、插入的操作中都会自动的帮我们加上 X 锁
    为 SELECT 语句加 X 锁是解决幻读的核心,加锁语句:SELECT … FOR UPDATE
  3. 意向锁(Intention Locks
    这是一个表级锁,其用法是:如果我们希望在一个表上加一个表级锁,那么加锁的前提一定是要先确保整个表没有与其互斥的锁,怎么确定?最简单的方式就是将整个表扫描一遍,这将会带来很大的性能开销,所以引入了意向锁:当一个事务试图对一个表添加行级锁时,无论加锁是否成功,都会在表上方再加一个对应意向锁(IX 或者 IS),当令事务试图加表级锁时,就先看这个表上是否有与其互斥的意向锁,有的话就只能通过意向锁撤销后再次加锁,这样就避免了全表扫描。

锁算法

锁算法大都是 InnoDB 的行级锁,在使用时与锁模式结合来使用。

  1. 记录锁
    针对的是索引中的一条实际的真正存在的记录
  2. 间隙锁
    锁住索引中一段开区间,是两个相邻的真实记录之间的一个范围。
  3. 临键锁
    其实就是一个间隙锁的基础上,再为右边的那条真实记录也给加上锁,也就是一个左开右闭的区间;在为范围的 SELECT 语句加锁时,实际上使用的都是临键锁
  4. 意向插入锁
    我们已经知道在指定插入语句的时候会自动加上 X 锁,如果这段范围被加上了临键锁怎么办?就可以使用意向插入锁,这个范围的意向插入锁需要顺序执行,防止后插入的数据生效导致数据不一致。
  5. 自增锁
    这是一个特殊的表级锁。当我们向表中插入数据并且使用了自增主键时就会添加自增锁,自增锁只会与自增锁之间互斥。通过这种方式保证了自增 id 的唯一性。
小码农 & GPT调教糕手
最后更新于 2025-10-31