mysql锁机制详情
MySQL 中的锁机制是保证数据一致性和并发控制的核心。其锁系统较为复杂,可以按粒度、类型和行为等不同维度进行分类。以下是主要的锁类型及其分类:
一、按锁的粒度划分(范围)
全局锁:
范围: 整个数据库实例。
作用: 对整个数据库实例进行只读锁定,常用于全库逻辑备份(如
mysqldump
配合--single-transaction
选项失败时的备选方案)。命令:
FLUSH TABLES WITH READ LOCK
(FTWRL)。影响: 阻塞所有其他会话的写操作(DDL, DML)和部分读操作(需要写临时表的 SELECT)。
释放: 显式执行
UNLOCK TABLES
或持有锁的会话终止表级锁:
范围: 整张表。
类型:
显式表锁:
表读锁 (
LOCK TABLES ... READ
): 持有锁的会话可以读该表(但不能写),其他会话也可以读该表,但任何会话都不能写(包括持有锁的会话)。表写锁 (
LOCK TABLES ... WRITE
): 持有锁的会话可以读写该表,其他会话不能读写该表。释放: 显式执行
UNLOCK TABLES
或会话终止。注意:
LOCK TABLES
语法会隐式释放该会话之前持有的任何表锁,并且在持有显式表锁期间,该会话只能访问被显式锁定的表。隐式表锁 (元数据锁 - MDL):
范围: 表结构(元数据)。
作用: 由 MySQL Server 层自动管理,用于保护表结构不被并发修改(如防止在查询进行时执行
ALTER TABLE
)。行为: 对表进行增删改查(DML)时自动加 MDL 读锁;对表结构进行修改(DDL)时自动加 MDL 写锁。读锁之间兼容,读锁与写锁、写锁与写锁之间互斥。
注意: 长时间未提交的事务持有 MDL 读锁会阻塞 DDL 操作(需要 MDL 写锁),反之亦然,是常见的阻塞场景。
意向锁 (Intention Locks):
范围: 表级锁。
类型:
意向共享锁 (Intention Shared Lock, IS): 表示事务打算在表中的某些行上加共享锁 (S)。
意向排他锁 (Intention Exclusive Lock, IX): 表示事务打算在表中的某些行上加排他锁 (X)。
作用: 是 InnoDB 支持行锁的基础机制。它们本身不锁定行,而是表明一个事务“有意向”在更细粒度(行)上加哪种类型的锁。目的是在表级快速判断是否存在行级锁冲突,避免逐行检查。
兼容性:
表级 IS 锁和 IX 锁之间是兼容的(因为意向锁只表示“意向”,不锁定实际行)。
IS/IX 锁与表级 S 锁和 X 锁的兼容性需要具体分析(见下文按类型划分)。
自动加锁: 事务在给一行加 S 锁之前,必须先获得该表的 IS 锁(或更强的锁);在给一行加 X 锁之前,必须先获得该表的 IX 锁(或更强的锁)
行级锁 (Row-Level Locks):
范围: 单行记录或行之间的间隙。这是 InnoDB 存储引擎的核心特性,实现了高并发。
类型 (InnoDB 特有的几种行锁算法):
记录锁 (Record Lock): 锁定索引中的一条具体记录。即使表没有定义索引,InnoDB 也会创建一个隐藏的聚簇索引来锁定记录。
间隙锁 (Gap Lock): 锁定索引记录之间的间隙(一个开区间),或者锁定第一条索引记录之前或最后一条索引记录之后的间隙。目的是防止其他事务在间隙中插入新记录(防止幻读)。仅存在于
REPEATABLE READ
隔离级别下。临键锁 (Next-Key Lock): 记录锁 + 间隙锁的组合。锁定一个索引记录以及该记录之前的间隙(左开右闭区间)。这是 InnoDB 在
REPEATABLE READ
隔离级别下默认的行锁算法。它同时解决了幻读和当前读的锁定问题。插入意向锁 (Insert Intention Lock): 一种特殊的间隙锁,由
INSERT
操作在插入行之前设置。作用是在同一个间隙中,多个事务尝试插入不同位置的行时,不会互相阻塞(只要插入的位置不冲突)。但它会与已经存在的间隙锁或临键锁冲突(阻塞插入)。注意: 行锁都是加在索引上的。如果查询没有使用索引,InnoDB 可能会退化为锁住整个表(实际上是锁住所有行,效果类似表锁,但机制还是行锁)
二、按锁的类型/行为划分(共享/独占)
共享锁 (Shared Lock, S Lock):
行为: 允许持有锁的事务读取数据。
兼容性: 多个事务可以同时持有同一资源的 S 锁(读读不阻塞)。
排他性: 与 X 锁互斥。一旦有事务持有 S 锁,其他事务就不能获得该资源的 X 锁。
加锁方式:
表级:
LOCK TABLES ... READ
行级:
SELECT ... LOCK IN SHARE MODE
(旧语法),SELECT ... FOR SHARE
(MySQL 8.0+ 推荐)排他锁 (Exclusive Lock, X Lock):
行为: 允许持有锁的事务读取或修改数据。
兼容性: 与其他任何锁(S 锁或 X 锁)都互斥。一旦有事务持有 X 锁,其他事务就不能获得该资源的 S 锁或 X 锁。
排他性: 最强,一次只能由一个事务持有。
加锁方式:
表级:
LOCK TABLES ... WRITE
行级:
SELECT ... FOR UPDATE
,UPDATE
,DELETE
,INSERT
(对插入的新行自动加 X 锁)意向共享锁 (IS) 和 意向排他锁 (IX):
如前所述,它们是表级锁,用于表示事务在行级上的“意向”(S 或 X)。
兼容矩阵 (表级):
X IX S IS X 冲突 冲突 冲突 冲突 IX 冲突 兼容 冲突 兼容 S 冲突 冲突 兼容 兼容 IS 冲突 兼容 兼容 兼容 关键点:
IX 和 IS 彼此兼容(意向不冲突)。
IX 和表级 S 锁冲突(因为 S 锁要求整个表只读,而 IX 表示要写某些行)。
IS 和表级 X 锁冲突(因为 X 锁要求独占写,而 IS 表示要读某些行)。
表级 X 锁与任何意向锁都冲突。
三、其他重要概念
自增锁 (AUTO-INC Lock):
一种特殊的表级锁,用于在具有
AUTO_INCREMENT
列的表上执行插入操作时。保证为插入语句生成连续的自增值(在语句执行期间持有,语句结束即释放)。
InnoDB 提供了不同的锁定模式(
innodb_autoinc_lock_mode
)来优化并发插入性能。元数据锁 (Metadata Lock, MDL):
如前所述,Server 层自动管理,保护表结构(schema),防止 DDL 和 DML 并发冲突
死锁 (Deadlock):
两个或多个事务互相等待对方释放锁,导致所有事务都无法继续执行的状态。
InnoDB 有死锁检测机制(默认开启,
innodb_deadlock_detect=ON
),会主动回滚其中一个事务(牺牲者)来打破死锁。也可以通过设置超时 (
innodb_lock_wait_timeout
) 来释放锁。