MySQL锁

全局锁

一般在做全库备份的时候用到。会阻塞写操作,只允许读请求。因此一般选在业务低峰期去做全库备份。

1
flush tables with read lock

表级锁

表锁

  1. 表共享读锁。多个线程能同时获取这个锁,获取锁的线程可以读这个表,但不能写这个表。MyISAM 处理读请求时,会获取该表的表共享读锁。而 InnoDB 默认是行锁,通过 MVCC 来处理读请求。
  2. 表独占写锁。只有一个线程能获取这个锁,它可以对表进行写操作。其它任何线程都不可以读这张表。
1
lock tables t_student read;

触发表锁:ALTER/DROP/TRUNCATE TABLE

意向锁

意向锁是表级锁,它的主要作用是避免全表扫描。(🌟号操作体现)
InnoDB 里面读某个 record,通过无锁的 MVCC 机制来实现,此时不会给表加意向锁。

意向锁和行级锁不冲突,意向锁之间也不冲突。

锁类型表级 S 锁(共享锁)表级 X 锁(排他锁)表级 IS 锁(意向共享锁)表级 IX 锁(意向排他锁)
表级 S 锁(共享锁)兼容冲突兼容兼容
表级 X 锁(排他锁)冲突冲突冲突冲突
表级 IS 锁(意向共享锁)兼容冲突兼容兼容
表级 IX 锁(意向排他锁)冲突冲突兼容兼容

意向读锁IS

1
 SELECT... LOCK IN SHARE MODE

当我们通过这种操作去读某一行数据时,会给这一行加上行级读锁,这时候数据库也会给这个表加上表级意向读锁

  1. 当有其它线程给某一行写锁时,根据索引判断这行是否加了读锁,如果没加,写锁可以被加上;如果这行已经加了读锁,则不能加写锁。
  2. 当有其它线程给全表写锁时,会发现表已经有意向读锁,因此不能完成写操作。🌟
  3. 当有其它线程给某一行/全表读锁时,不冲突

意向写锁IX

1
select ... for update;

这个操作给这个表加上意向写锁,并且给该行加上写锁。

  1. 当有其它线程给某一行写锁时,根据索引判断这行是否已经有写锁,如果没有,写锁可以被加上;如果这行已经加了写锁,则不能再加写锁。
  2. 当有其它线程给全表写锁时,会发现表已经有意向写锁,因此不能完成写操作。🌟
  3. 当有其它线程给某一行读锁时,根据索引判断是不是同一行,如果是,则读锁不能加上;如果不是,可以加上
  4. 当有其它线程给全表读锁时,可以完成。

行锁

行锁是一种精确到数据库表中某一行数据的锁.

行级锁 Record Lock

区分行级读锁/写锁

间隙锁(Gap Lock)

间隙锁锁定的是两个相邻索引记录之间的 “间隙”,这里的间隙包括左开右开、左闭右开、左开右闭三种形式。

间隙锁是 InnoDB 在**可重复读(Repeatable Read, RR)**隔离级别下特有的一种锁,用于锁定索引记录之间的“间隙”(即两个索引值之间的范围)。

它的核心作用是 防止其他事务在间隙中插入新数据,从而解决幻读问题。

可能会产生死锁问题。

Next - Key Lock

Next - Key Lock 是一种组合锁,它由行锁和间隙锁组成。它锁定的范围是左开右闭区间。
整合行锁与间隙锁:它既可以锁定精确的数据行(行锁的功能),又可以锁定数据行之间的间隙(间隙锁的功能),提供更全面的保护。

面试问题

  1. 在 MySQL 中,如果一条 UPDATE 语句没有带 WHERE 条件,InnoDB 引擎会对整个表加 IX 锁(意向排他锁),并对所有行加 X 锁(排他锁),确保事务的原子性和一致性。而 MyISAM 引擎会对整个表加 写锁(排他锁),阻塞其他所有读写操作。
  2. 如果 UPDATE 语句带了 WHERE 条件,InnoDB 引擎会对符合条件的行加 X 锁(排他锁),并在可重复读隔离级别下加 间隙锁 防止幻读。如果 WHERE 条件使用了索引,InnoDB 会通过索引锁定对应的行;如果没有索引,则可能升级为表级锁。而 MyISAM 引擎无论是否有 WHERE 条件,都会对整个表加 写锁(排他锁)。