欢迎光临
我们一直在努力

MySQL锁的分类及具体作用

在数据库系统中,锁是保证数据一致性和并发控制的核心机制。MySQL作为流行的关系型数据库,提供了丰富多样的锁策略来应对不同的并发场景。理解MySQL锁的分类及其作用,对于优化数据库性能、避免死锁以及保证数据正确性至关重要。本文将从锁的粒度、锁的功能两个维度,系统梳理MySQL中的各类锁,并详细说明每种锁的用途、加锁方式及注意事项。


先贴张图方便理解

一、按锁的粒度分类

锁的粒度指的是锁定的范围大小,粒度越细,并发能力越强,但加锁开销也越大。MySQL中按粒度可分为:全局锁、表级锁和行级锁。

1. 全局锁

全局锁是对整个数据库实例加锁,加锁后整个数据库处于只读状态。通常用于全库逻辑备份,确保备份数据的一致性。

  • 加锁语句:

    FLUSH TABLES WITH READ LOCK;

  • 作用:阻塞所有数据更新操作(INSERT、UPDATE、DELETE)和表结构变更(ALTER、DROP等),仅允许读取。

  • 缺点:导致业务停滞,无法处理写请求。

  • 优化方案:

    • 对于使用InnoDB存储引擎的表,可利用事务的可重复读隔离级别,在备份时开启一个事务,利用MVCC(多版本并发控制)创建一致性快照,避免加全局锁。

    • 使用mysqldump工具时,添加–single-transaction参数,该选项会在备份前启动一个事务,基于快照进行备份,从而避免全局锁。

2. 表级锁

表级锁锁定整张表,实现简单,开销较小,但并发度较低。MyISAM和InnoDB都支持表级锁。

2.1 表锁

通过LOCK TABLES语句显式加锁,可以加共享锁(读锁)或排他锁(写锁)。

  • 表级共享锁:

    LOCK TABLES user READ;

    阻止其他会话对表进行写操作,当前会话只能读该表,不能访问其他表。

  • 表级排他锁:

    LOCK TABLES user WRITE;

    阻止其他会话对该表进行任何读/写操作,当前会话可读写该表,但不能访问其他表。

2.2 元数据锁(MDL锁)

MDL锁是MySQL自动管理的表级锁,用于保护表结构定义。当对一个表执行SELECT(加MDL读锁)时,会阻止其他会话对该表执行DDL操作(如ALTER TABLE),直到当前事务提交。

  • 释放时机:事务提交后自动释放。

  • 作用:防止在查询过程中表结构被修改,保证元数据的一致性。

2.3 意向锁

意向锁是InnoDB自动维护的表级锁,用于快速判断表级锁与行级锁的兼容性,避免逐行检查。用户无法手动干预。

  • 意向共享锁(IS锁):事务准备给表中的某些行加共享锁(S锁)时,先在表上加IS锁。

  • 意向排他锁(IX锁):事务准备给表中的某些行加排他锁(X锁)时,先在表上加IX锁。

意向锁的兼容规则:

  • 意向锁之间相互兼容(IS与IS、IS与IX、IX与IX均不冲突)。

  • 意向锁与行级S锁/X锁也兼容,因为它们是在不同粒度上的锁。

  • 但意向排他锁(IX)与表级共享锁(S)或表级排他锁(X)互斥,意向共享锁(IS)与表级共享锁(S)兼容,与表级排他锁(X)互斥。

表级锁 \\ 意向锁IS锁IX锁
S锁(共享表锁) 兼容 互斥
X锁(独占表锁) 互斥 互斥
2.4 自增锁(AUTO-INC锁)

自增锁是一种特殊的表级锁,用于保证自增列(AUTO_INCREMENT)值的唯一性和连续性。事务向包含自增列的表插入数据时,需要获取自增锁。

  • 传统模式:语句执行期间持有自增锁,直到语句结束才释放,影响并发插入性能。

  • 优化模式:MySQL 5.1.22起提供innodb_autoinc_lock_mode参数控制自增锁行为:

    • 0(传统模式):采用AUTO-INC锁,语句执行完释放。

    • 1(连续模式,MySQL 8.0前默认):普通INSERT申请到自增值后立即释放锁;批量插入(如INSERT … SELECT)需等待语句结束释放。

    • 2(交错模式,MySQL 8.0后默认):使用轻量级互斥锁,多条插入语句可并发执行,性能最高。但需将binlog格式设置为ROW,以保证主从数据一致性。

3. 行级锁

行级锁仅锁定具体的数据行,并发度高,是InnoDB的核心特性。MyISAM不支持行级锁。

3.1 记录锁(Record Lock)

锁定单个行记录,是最基本的行锁。

  • 加锁方式:

    — 加共享记录锁(S锁)
    SELECT … LOCK IN SHARE MODE;
    — 或
    SELECT … FOR SHARE; — MySQL 8.0+

    — 加排他记录锁(X锁)
    SELECT … FOR UPDATE;

  • 特性:

    • 对某行加S锁后,其他事务可加S锁,但不能加X锁。

    • 对某行加X锁后,其他事务不能加任何锁(S或X)。

    • 锁在事务提交或回滚后释放。

例如,对id=2的记录加X锁:

BEGIN;
SELECT * FROM user WHERE id = 2 FOR UPDATE;
— 其他事务无法修改id=2的记录
COMMIT;

3.2 间隙锁(Gap Lock)

间隙锁锁定一个范围(开区间),但不包括记录本身,目的是防止其他事务在该范围内插入新记录,从而避免幻读。

  • 示例:表中已有id=1,2,3,5的记录,间隙锁锁定(1,5)范围,即禁止在id=2,3的位置插入新记录,但不影响id=5的记录。

  • 作用范围:仅在可重复读(REPEATABLE READ)隔离级别下生效。

  • 兼容性:不同事务可在同一间隙上加间隙锁,因为间隙锁只阻塞插入,不阻塞查询。

3.3 临键锁(Next-Key Lock)

临键锁是记录锁与间隙锁的组合,锁定一个范围,并包含记录本身。它是InnoDB在可重复读级别下解决幻读的主要手段。

  • 示例:锁定(1,5]范围,即锁住id=2,3,5的记录,同时防止在(1,5)范围内插入新记录。

  • 特性:不同事务对相同范围的X型临键锁是互斥的。

3.4 插入意向锁

插入意向锁是一种特殊的间隙锁,表示事务准备在某个间隙中插入新记录。它由InnoDB自动管理,用户无法干预。

  • 作用:协调多个事务在同一个间隙内的插入操作,提高并发度。

  • 兼容规则:

    • 如果事务A持有某个间隙的间隙锁,事务B想要在同一间隙加插入意向锁,则B必须等待A释放间隙锁。

    • 如果多个事务准备在同一个间隙的不同位置插入记录,它们的插入意向锁可以共存,互不阻塞。

    • 插入意向锁与间隙锁互斥,但与记录锁不直接冲突(记录锁锁住的是记录本身)。


二、按锁的功能分类

无论是表级锁还是行级锁,从功能上都可以分为共享锁(S锁)和排他锁(X锁)。

  • 共享锁(S锁):读锁,事务读取数据时获取。允许其他事务同时加S锁,但不允许加X锁。

  • 排他锁(X锁):写锁,事务修改数据时获取。不允许其他事务再加任何锁(S或X)。

兼容性矩阵:

锁类型S锁X锁
S锁 兼容 互斥
X锁 互斥 互斥

加锁语句示例:

— 加共享锁
SELECT … LOCK IN SHARE MODE; — MySQL 5.x
SELECT … FOR SHARE; — MySQL 8.x

— 加排他锁
SELECT … FOR UPDATE;


三、扩展:快照读与当前读

理解锁机制离不开对MySQL读取模式的认识。InnoDB支持两种读取方式:

1. 快照读

  • 利用MVCC机制,读取的是记录的历史版本(快照),不加锁,因此不会阻塞其他事务。

  • 仅在读已提交(RC)和可重复读(RR)隔离级别下生效。

  • RC级别下,每次执行SELECT都会获取最新的快照;RR级别下,仅在事务开始时获取一次快照,后续读取同一快照。

2. 当前读

  • 读取记录的最新版本,并对读取的记录加锁(S锁或X锁),确保其他事务不能修改这些记录。

  • 常见当前读操作:

    SELECT … FOR UPDATE; — 加X锁
    SELECT … LOCK IN SHARE MODE; — 加S锁
    INSERT;
    UPDATE;
    DELETE;


四、总结

MySQL的锁机制复杂而精细,理解不同锁的作用和适用场景,有助于我们编写高效、可靠的并发事务。下表简要总结了主要锁类型及其用途:

锁类型粒度主要作用
全局锁 数据库 全库备份,保证一致性
表锁 显式锁定整张表,用于特定操作
元数据锁 保护表结构,防止DDL与DML冲突
意向锁 快速判断表锁与行锁的兼容性
自增锁 保证自增列的唯一性
记录锁 锁定单行记录
间隙锁 间隙 防止幻读,禁止在范围内插入
临键锁 行+间隙 记录锁与间隙锁的组合,解决幻读
插入意向锁 间隙 协调并发插入,提高插入性能

在实际开发中,合理选择隔离级别、优化SQL语句、避免长事务,都能减少锁冲突,提升系统并发能力。

赞(0)
未经允许不得转载:171主机测评 » MySQL锁的分类及具体作用
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址