首页 >> 基础教程

mysql锁机制详情

      MySQL 中的锁机制是保证数据一致性和并发控制的核心。其锁系统较为复杂,可以按粒度类型行为等不同维度进行分类。以下是主要的锁类型及其分类:

一、按锁的粒度划分(范围)

  1. 全局锁:

    1. 范围: 整个数据库实例。

    2. 作用: 对整个数据库实例进行只读锁定,常用于全库逻辑备份(如 mysqldump 配合 --single-transaction 选项失败时的备选方案)。

    3. 命令: FLUSH TABLES WITH READ LOCK (FTWRL)。

    4. 影响: 阻塞所有其他会话的写操作(DDL, DML)和部分读操作(需要写临时表的 SELECT)。

    5. 释放: 显式执行 UNLOCK TABLES 或持有锁的会话终止

  2. 表级锁:

    1. 范围: 整张表。

    2. 类型:

      1. 显式表锁:

        1. 表读锁 (LOCK TABLES ... READ): 持有锁的会话可以读该表(但不能写),其他会话也可以读该表,但任何会话都不能写(包括持有锁的会话)。

        2. 表写锁 (LOCK TABLES ... WRITE): 持有锁的会话可以读写该表,其他会话不能读写该表。

        3. 释放: 显式执行 UNLOCK TABLES 或会话终止。

        4. 注意: LOCK TABLES 语法会隐式释放该会话之前持有的任何表锁,并且在持有显式表锁期间,该会话只能访问被显式锁定的表。

      2. 隐式表锁 (元数据锁 - MDL):

        1. 范围: 表结构(元数据)。

        2. 作用: 由 MySQL Server 层自动管理,用于保护表结构不被并发修改(如防止在查询进行时执行 ALTER TABLE)。

        3. 行为: 对表进行增删改查(DML)时自动加 MDL 读锁;对表结构进行修改(DDL)时自动加 MDL 写锁。读锁之间兼容,读锁与写锁、写锁与写锁之间互斥。

        4. 注意: 长时间未提交的事务持有 MDL 读锁会阻塞 DDL 操作(需要 MDL 写锁),反之亦然,是常见的阻塞场景。

      3. 意向锁 (Intention Locks):

        1. 范围: 表级锁。

        2. 类型:

          1. 意向共享锁 (Intention Shared Lock, IS): 表示事务打算在表中的某些行上加共享锁 (S)。

          2. 意向排他锁 (Intention Exclusive Lock, IX): 表示事务打算在表中的某些行上加排他锁 (X)。

        3. 作用: 是 InnoDB 支持行锁的基础机制。它们本身不锁定行,而是表明一个事务“有意向”在更细粒度(行)上加哪种类型的锁。目的是在表级快速判断是否存在行级锁冲突,避免逐行检查。

        4. 兼容性:

          1. 表级 IS 锁和 IX 锁之间是兼容的(因为意向锁只表示“意向”,不锁定实际行)。

          2. IS/IX 锁与表级 S 锁和 X 锁的兼容性需要具体分析(见下文按类型划分)。

        5. 自动加锁: 事务在给一行加 S 锁之前,必须先获得该表的 IS 锁(或更强的锁);在给一行加 X 锁之前,必须先获得该表的 IX 锁(或更强的锁)

  3. 行级锁 (Row-Level Locks):

    1. 范围: 单行记录或行之间的间隙。这是 InnoDB 存储引擎的核心特性,实现了高并发。

    2. 类型 (InnoDB 特有的几种行锁算法):

      1. 记录锁 (Record Lock): 锁定索引中的一条具体记录。即使表没有定义索引,InnoDB 也会创建一个隐藏的聚簇索引来锁定记录。

      2. 间隙锁 (Gap Lock): 锁定索引记录之间的间隙(一个开区间),或者锁定第一条索引记录之前或最后一条索引记录之后的间隙。目的是防止其他事务在间隙中插入新记录(防止幻读)仅存在于 REPEATABLE READ 隔离级别下。

      3. 临键锁 (Next-Key Lock): 记录锁 + 间隙锁的组合。锁定一个索引记录以及该记录之前的间隙(左开右闭区间)。这是 InnoDB 在 REPEATABLE READ 隔离级别下默认的行锁算法。它同时解决了幻读和当前读的锁定问题。

      4. 插入意向锁 (Insert Intention Lock): 一种特殊的间隙锁,由 INSERT 操作在插入行之前设置。作用是在同一个间隙中,多个事务尝试插入不同位置的行时,不会互相阻塞(只要插入的位置不冲突)。但它会与已经存在的间隙锁或临键锁冲突(阻塞插入)。

    3. 注意: 行锁都是加在索引上的。如果查询没有使用索引,InnoDB 可能会退化为锁住整个表(实际上是锁住所有行,效果类似表锁,但机制还是行锁)

 二、按锁的类型/行为划分(共享/独占)

  1. 共享锁 (Shared Lock, S Lock):

    1. 行为: 允许持有锁的事务读取数据。

    2. 兼容性: 多个事务可以同时持有同一资源的 S 锁(读读不阻塞)。

    3. 排他性: 与 X 锁互斥。一旦有事务持有 S 锁,其他事务就不能获得该资源的 X 锁。

    4. 加锁方式:

      1. 表级: LOCK TABLES ... READ

      2. 行级: SELECT ... LOCK IN SHARE MODE (旧语法), SELECT ... FOR SHARE (MySQL 8.0+ 推荐)

  2. 排他锁 (Exclusive Lock, X Lock):

    1. 行为: 允许持有锁的事务读取或修改数据。

    2. 兼容性: 与其他任何锁(S 锁或 X 锁)都互斥。一旦有事务持有 X 锁,其他事务就不能获得该资源的 S 锁或 X 锁。

    3. 排他性: 最强,一次只能由一个事务持有。

    4. 加锁方式:

      1. 表级: LOCK TABLES ... WRITE

      2. 行级: SELECT ... FOR UPDATEUPDATEDELETEINSERT (对插入的新行自动加 X 锁)

  3. 意向共享锁 (IS) 和 意向排他锁 (IX):

    1. 如前所述,它们是表级锁,用于表示事务在行级上的“意向”(S 或 X)。

    2. 兼容矩阵 (表级):


      • XIXSIS
        X冲突冲突冲突冲突
        IX冲突兼容冲突兼容
        S冲突冲突兼容兼容
        IS冲突兼容兼容兼容
      1. 关键点:

        1. IX 和 IS 彼此兼容(意向不冲突)。

        2. IX 和表级 S 锁冲突(因为 S 锁要求整个表只读,而 IX 表示要写某些行)。

        3. IS 和表级 X 锁冲突(因为 X 锁要求独占写,而 IS 表示要读某些行)。

        4. 表级 X 锁与任何意向锁都冲突。

三、其他重要概念

  1. 自增锁 (AUTO-INC Lock):

    1. 一种特殊的表级锁,用于在具有 AUTO_INCREMENT 列的表上执行插入操作时。

    2. 保证为插入语句生成连续的自增值(在语句执行期间持有,语句结束即释放)。

    3. InnoDB 提供了不同的锁定模式(innodb_autoinc_lock_mode)来优化并发插入性能。

  2. 元数据锁 (Metadata Lock, MDL):

    1. 如前所述,Server 层自动管理,保护表结构(schema),防止 DDL 和 DML 并发冲突

  3. 死锁 (Deadlock):

    1. 两个或多个事务互相等待对方释放锁,导致所有事务都无法继续执行的状态。

    2. InnoDB 有死锁检测机制(默认开启,innodb_deadlock_detect=ON),会主动回滚其中一个事务(牺牲者)来打破死锁。

    3. 也可以通过设置超时 (innodb_lock_wait_timeout) 来释放锁。


最新文章
mysql分页问题2025-08-04
千万数据先insert和先建索引哪个快2025-08-04
MySQL 中大小表关联查询如何优化2025-08-04
sql技巧-每个班年龄排前两名的人2025-08-03
MySQL 导致 cpu 飙升的话,要怎么处理呢?2025-07-29
MySQL 中为千万级大表添加字段2025-07-29
mysql中百万级别以上的数据如何删除2025-07-29
分库分表带来的问题2025-07-29
mysql中常用的分库分表中间件有哪些2025-07-29
mysql不停机扩容2025-07-29
备案号:蜀ICP备2023042032号-1