1. 表级锁

意向锁解决了一个表加了行锁和读锁的冲突问题



2.行级锁




3.MVCC实现原理




MySQL 锁机制详解:从原理到实战,一文搞懂行锁、表锁、意向锁
一、为什么要学 MySQL 锁?
并发场景下,多个事务同时操作数据库,会出现脏读、不可重复读、幻读 ,还会引发更新丢失、数据错乱。锁就是 MySQL 解决并发竞争、保证数据隔离性与一致性的核心机制。
简单理解:锁就是数据库给数据加的 "权限门禁",有人在用,别人就得排队或禁止操作。
二、MySQL 锁的整体分类
按粒度分:
- 表级锁:锁住整张表
- 行级锁:锁住某一行记录
- 页级锁:锁住数据页(MyISAM 不支持,InnoDB 少见)
按类型分:
- 共享锁(S 锁、读锁):可读不可改,多人可同时加 S 锁
- 排他锁(X 锁、写锁):不可读也不可改,独占
三、表级锁(MyISAM 默认)
1. 特点
- 粒度最大,开销小,加锁快
- 不会死锁
- 并发极差,一锁锁整张表
2. 分类
- 表共享读锁:所有人可以读,不能写
- 表排他写锁:自己可读写,其他人啥都不能做
3. 适用场景
查询多、更新少的业务;MyISAM 引擎专用。
缺点:只要有一个事务写表,所有其他事务都阻塞,高并发完全扛不住。
四、行级锁(InnoDB 默认核心)
InnoDB 支持事务、支持行锁,也是业务开发最常用的锁。
1. 特点
- 粒度最小,只锁一行
- 加锁慢、开销大
- 会产生死锁
- 并发性能极高
2. 行锁两大类型
- 行共享锁 S :
select ... lock in share mode - 行排他锁 X :
select ... for update/ 增删改默认加 X 锁
3 重点:行锁生效前提
必须走索引! 如果没走索引,MySQL 会降级为表锁,直接锁整张表,并发直接废掉。
五、意向锁(InnoDB 自动加)
很多人看不懂意向锁,其实很简单:意向锁是表级辅助锁,标记 "我要在表里面加行锁了",用来快速判断表是否有行锁冲突,不用遍历每一行。
两种:
- 意向共享 IS:事务打算给行加 S 锁
- 意向排他 IX:事务打算给行加 X 锁
兼容性口诀:
- IS 和 IS、IX 都兼容
- IX 和 S、X 基本互斥,避免表锁与行锁冲突
意向锁人工不用管,InnoDB 自动维护,只需要懂原理即可。
六、快照读 & 当前读(锁的底层关键)
1. 快照读
不加锁,读历史版本数据 ,基于 MVCC普通 select * from table 就是快照读,无锁、快、不阻塞。
2. 当前读
读取最新数据,加行锁包括:
- insert、update、delete
- select ... for update
- select ... lock in share mode
七、三种经典锁问题
1. 脏读
事务读到了其他事务未提交的数据。
2. 不可重复读
同一事务内,两次查询同一行,结果不一样(被其他事务修改提交)。
3. 幻读
同一事务范围查询,前后行数不一样,其他事务插入 / 删除了新数据。
InnoDB 通过 Next-Key 临键锁 解决幻读。
八、临键锁 Next-Key(重点面试必问)
InnoDB 默认行锁算法,三合一:记录锁 + 间隙锁 + 临键锁
- 记录锁:锁当前存在的行
- 间隙锁:锁两条数据中间的空隙,禁止插入
- 临键锁:锁住索引左开右闭区间,彻底解决幻读
九、死锁产生与避免
1. 死锁条件
- 互斥
- 持有并等待
- 不可剥夺
- 循环等待
2. 如何避免死锁
- 统一 SQL 执行顺序
- 尽量按主键 / 索引加锁
- 事务尽量短小,尽早提交
- 避免长事务
十、开发实战避坑总结
- 能用 InnoDB 别用 MyISAM,高并发必须行锁
- 行锁一定要走索引,否则降级表锁
- 普通查询用快照读,别乱用
for update - 批量更新尽量缩小范围,减少锁范围
- 事务别写太长,防止锁持有时间过久
- 理解 MVCC + 临键锁,就能吃透 MySQL 并发