10人参与 • 2026-03-17 • Mysql
在数据库并发环境中,多个事务可能同时访问同一份数据。如果没有合理的并发控制机制,就会出现数据不一致、脏读、幻读等问题。
为了解决这些问题,mysql 在存储引擎层提供了一套完整的 锁机制(lock mechanism),用于控制多个事务对数据的访问顺序。
从整体结构上看,mysql 的锁可以按照 锁的粒度 分为两大类:
mysql 锁
│
├── 表级锁
│ ├── 表锁(lock tables)
│ ├── 元数据锁(mdl lock)
│ └── 意向锁(intention lock)
│
└── 行级锁(innodb)
├── 记录锁(record lock)
├── 间隙锁(gap lock)
└── 临键锁(next-key lock)下面分别进行介绍。
表级锁是 作用在整张表上的锁,也就是说,一旦某个事务对表加锁,其他事务访问该表就会受到限制。
表级锁的特点:
mysql 中表级锁主要包括三种:
显式表锁是通过 sql 语句手动对表加锁:
lock tables table_name read; lock tables table_name write;
释放锁:
unlock tables;
lock tables user read;
含义:
也就是说:
读读可以并发,读写互斥。
lock tables user write;
含义:
unlock tables因此 write 锁是 排他锁。
mdl(metadata lock)是 mysql 自动维护的一种锁,不需要手动加锁。
它的作用是:
防止在执行 dml 操作时表结构被修改。
例如:
执行查询:
select * from user;
mysql 会自动添加:mdl 读锁
如果执行:
alter table user add column age int;
mysql 会添加:mdl 写锁
mdl 写锁会阻塞其他事务的读写操作,从而避免 ddl 与 dml 冲突。
在生产环境中,如果一个事务长时间未提交,可能会导致:
alter table 一直等待
这往往就是 mdl 锁导致的阻塞问题。
意向锁是 innodb 在 表级别维护的一种锁标记,用于配合行锁使用。
它的核心作用是:
在事务对某一行数据加锁之前,先在表级别声明加锁意图。
例如:
select * from user where id = 1 for update;
innodb 会做两件事:
1️⃣ 在表上加 意向排他锁(ix)
2️⃣ 在对应记录上加 行排他锁(x锁)
意向锁(intention lock)不是只有 ix 一种,而是一个锁的类别,其中包括两种类型:
也就是说:
| 锁类型 | 含义 |
|---|---|
| is | 表示事务准备在某些行上加 共享锁(s锁) |
| ix | 表示事务准备在某些行上加 排他锁(x锁) |
举个例子
1️⃣ 查询加共享锁
select * from user where id = 1 lock in share mode;
innodb 会:
表:is 行:s
2️⃣ 更新数据
update user set age = 20 where id = 1;
innodb 会:
表:ix 行:x
假设没有意向锁:
当一个事务想给整张表加锁时,就必须扫描整张表,查看是否存在行锁,这样效率非常低。
而有了意向锁之后:
只需要检查表级锁即可判断是否存在行锁。
因此:
意向锁的本质是 用于快速判断表中是否存在行锁的标记。
一句话总结:意向锁(intention lock)是 innodb 在表级维护的一种锁标记,用于表示事务即将在某些行上加锁,其主要类型包括意向共享锁(is)和意向排他锁(ix)。
行级锁是 innodb 存储引擎支持的一种锁机制。
相比表锁,它的特点是:
行锁锁定的是 一条具体记录,而不是整张表。
记录锁是最基本的行锁,它只锁定某一条记录。
例如:
select * from user where id = 1 for update;
只会锁住:
id = 1 这一条记录
其他记录仍然可以被访问。
记录锁通常分为:
它们满足:
读读可以并发 读写互斥 写写互斥
间隙锁锁住的不是具体记录,而是 索引之间的空隙。
例如:
select * from user where score > 100 for update;
如果当前数据为:
100 150 200
间隙锁可能锁住:
(100 , +∞)
这样其他事务就 不能插入 score=120 的数据。
间隙锁的主要作用是:
防止幻读。
需要注意:
间隙锁 不会锁住已有记录,只锁住区间。
next-key lock 是:
record lock + gap lock
也就是说:
既锁住记录,又锁住间隙。
例如:
select * from user where age between 20 and 30 for update;
假设表中存在:
20 25 30
innodb 可能锁住:
(-∞,20] (20,25] (25,30] (30,+∞)
这样不仅锁住已有记录,还锁住记录之间的间隙。
因此:
next-key lock 可以彻底防止幻读。
到此这篇关于mysql中锁的分类与加锁方式小结的文章就介绍到这了,更多相关mysql锁的分类与加锁内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
您想发表意见!!点此发布评论
版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。
发表评论