mysql 的锁有哪些?

题目

mysql 的锁有哪些?

正确答案
MySQL 中的锁机制复杂且多样,主要用于控制并发访问,保证数据一致性。根据不同的分类方式,锁可以分为以下几类:

一、按锁的粒度划分

  1. 全局锁(Global Lock)
    • 作用范围:整个数据库实例。
    • 功能:锁定所有表,使数据库处于只读状态(除 SELECTSHOW 等读操作外,DMLDDL、事务提交等均会被阻塞)。
    • 典型场景:逻辑备份(FLUSH TABLES WITH READ LOCK),确保备份期间数据一致性。
  2. 表级锁(Table-level Lock)
    • 作用范围:整张表。
    • 类型:
      • 表共享读锁(Table Read Lock):多个事务可同时读表,写操作被阻塞。
      • 表独占写锁(Table Write Lock):仅持有锁的事务可读写表,其他事务读写均被阻塞。
    • 特点:开销小、加锁快,并发度低,适用于 MyISAM 等非事务引擎(InnoDB 也支持,但通常用行级锁)。
    • 特殊表锁:
      • 意向锁(Intention Lock)InnoDB 为支持行级锁而引入,表明事务稍后会对表中的行加读锁或写锁(分为意向共享锁 IS 和意向排他锁 IX)。
      • 自增锁(Auto-inc Lock):插入含自增列(AUTO_INCREMENT)的表时,MySQL 会锁定自增计数器,保证自增列唯一性(可通过 innodb_autoinc_lock_mode 调整模式)。
  3. 行级锁(Row-level Lock)
    • 作用范围:表中的单行数据。
    • 仅 InnoDB 引擎支持,是 MySQL 中粒度最细的锁,并发度最高。
    • 类型:
      • 共享锁(S Lock,读锁):事务持有后,其他事务可加 S 锁但不可加 X 锁(允许多个事务同时读)。
      • 排他锁(X Lock,写锁):事务持有后,其他事务不可加任何锁(仅持有锁的事务可读写)。

二、按锁的功能划分(InnoDB 特有)

  1. 记录锁(Record Lock)
    • 锁定单行记录,防止其他事务修改或删除该记录。
    • 例如:SELECT * FROM t WHERE id=1 FOR UPDATE 会对 id=1 的行加 X 锁。
  2. 间隙锁(Gap Lock)
    • 锁定索引记录之间的间隙(或范围),防止其他事务在间隙中插入新记录,解决幻读问题。
    • 仅在 REPEATABLE READ 及以上隔离级别生效。
    • 例如:SELECT * FROM t WHERE id BETWEEN 5 AND 10 FOR UPDATE 会锁定 5~10 之间的间隙,阻止插入 id=6 等新行。
  3. 临键锁(Next-Key Lock)
    • 记录锁 + 间隙锁的组合,锁定记录本身及相邻的间隙,是 InnoDB 在 REPEATABLE READ 级别下的默认行锁算法。
    • 例如:索引列有 1,3,5 时,锁定 3 会同时锁定 (1,3] 范围(包含 3 本身及 1~3 之间的间隙)。
  4. 插入意向锁(Insert Intention Lock)
    • 事务插入数据时,在间隙中预先声明的意向锁,多个事务可在同一间隙插入不同位置的记录,互不阻塞。
    • 例如:两个事务同时插入 id=4 和 id=6 到 1~7 的间隙中,不会冲突。

三、按锁的模式划分

  • 乐观锁:假设并发冲突少,不加锁直接操作,提交时通过版本号(如 version 字段)或时间戳检查是否冲突(冲突则重试)。
     
    实现:UPDATE t SET num=num-1 WHERE id=1 AND version=2(需手动实现)。
  • 悲观锁:假设并发冲突多,操作前先加锁(如行级锁、表锁),阻塞其他事务直到释放锁(MySQL 内置的锁多为悲观锁)。

总结

  • InnoDB 主要依赖行级锁(记录锁、间隙锁、临键锁)和意向锁,支持高并发;
  • 表级锁适用于非事务引擎或简单场景;
  • 全局锁用于全库只读操作(如备份)。
     
    实际使用中,需根据业务场景和隔离级别合理设计索引和 SQL,避免死锁和性能问题。