Day03
1. MySQL的事务有哪些特性?
MySQL的事务遵循ACID原则。
- 原子性(Atomicity):事务中的操作要么全部执行成功,要么全部失败回滚。
- 一致性(Consistency):事务执行前后,数据库都处于一致状态,不会破坏数据的约束关系。
- 隔离性(Isolation):并发事务之间相互隔离,不会互相影响。
- 持久性(Durability):一旦事务提交,修改会永久保存到数据库中,即使系统宕机也不会丢失。
2. MySQL默认使用哪个隔离级别?
MySQL 默认的隔离级别是 可重复读(REPEATABLE READ),它可以防止脏读和不可重复读,并且通过 InnoDB 的间隙锁机制避免幻读问题,是性能和隔离性的平衡选择。
3. 间隙锁(Gap Lock)的原理
间隙锁是InnoDB为了防止幻读而引入的锁机制,他会锁住索引间的“空隙”,防止其他事务在范围内插入数据。主要在可重复读(REPEATABLE READ)隔离级别下使用,结合Next-Key Lock(记录锁 + 间隙锁)实现完整的范围保护。
InnoDB 中有三种锁:记录锁锁住已有记录,间隙锁锁住两个记录之间的范围,Next-Key Lock 是两者的组合,用于防止幻读。在范围查询时(如 BETWEEN),会使用 Next-Key Lock 加锁范围 + 记录;而主键等值查询时,只加记录锁,不加间隙锁。
锁类型 | 锁定范围 | 用途 | 是否锁住存在的数据 | 是否锁住不存在的数据 |
---|---|---|---|---|
记录锁 | 某一条具体的记录 | 防止修改现有数据 | ✅ 是 | ❌ 否 |
间隙锁 | 两条记录之间的间隙 | 防止插入新数据(防幻读) | ❌ 否 | ✅ 是 |
Next-Key Lock | 记录锁 + 间隙锁 | 防止幻读 + 锁住已有数据 | ✅ 是 | ✅ 是 |
4. 什么时候会加间隙锁?
间隙锁(Gap Lock)主要在 InnoDB 的可重复读(REPEATABLE READ)隔离级别下,执行范围查询并加锁语句(如 SELECT … FOR UPDATE、UPDATE、DELETE)时触发,用于防止幻读,即防止其他事务在间隙中插入新数据。
- 范围查询 + 加锁语句(如FOR UPDATE / FOR SHARE):SELECT * FROM user WHERE age > 20 FOR UPDATE; 会加间隙锁锁住“age > 20”范围,防止其他事务插入age = 25之类的新纪录。
- DELETE或UPDATE涉及范围时:DELETE FROM user WHERE age BETWEEN 20 AND 30;
UPDATE user SET status=‘inactive’ WHERE id < 100;- 二级索引范围查询:SELECT * FROM user WHERE name BETWEEN ‘A’ AND ‘M’ FOR UPDATE;
- 主键不存在的等值查询 + 加锁语句:SELECT * FROM user WHERE id = 100 FOR UPDATE; (id=100 不存在)
5. MySQL如何保证原子性?
MySQL通过InnoDB的undo日志机制来实现原子性,在事务执行过程中会记录修改前的数据;如果事务中途失败或执行ROLLBACK,就通过undo日志将数据恢复到事务开始前的状态,保证事务“要么全部执行,要么全部不执行”。
- undo 日志:记录数据被修改前的状态(如旧值)。
- 事务提交前,所有改动都可以通过 undo 回滚。
- 如果崩溃或 rollback,就用 undo 日志将改动撤销。
- 事务提交时,这些 undo 日志会被清理掉(或延迟清理)。
6. undo log撤销过程具体是怎么撤销的?
InnoDB 通过 undo log(回滚日志) 实现事务的原子性和一致性。每当对记录执行增删改操作时,InnoDB 都会把回滚所需的“原始信息”写入 undo log:
- 对于 插入操作(INSERT),undo log 记录插入记录的主键值,回滚时只需删除对应主键的数据;
- 对于 删除操作(DELETE),undo log 记录整条被删除的记录内容,回滚时重新插入该记录;
- 对于 更新操作(UPDATE),undo log 会记录被更新字段的旧值,回滚时把这些字段改回旧值。
当事务发生回滚时,InnoDB会根据undo log中的信息按相反方向逐步撤销操作,比如:delete → insert,update → 恢复旧值,从而保证事务要么全部执行,要么全部撤销,真正实现 原子性(A)。
此外,undo log 还是 MVCC 多版本并发控制的关键部分,用于生成数据的“历史快照”,让其他事务可以读取一致性视图。
7. 怎么决定建立哪些索引?
适合建立索引的场景:
- 唯一性强的字段:如商品编码、用户ID这类字段可唯一标识一条记录,索引能大幅提升查找效率。
- 经常作为WHERE条件的字段:索引能加快数据定位。
- 频繁参与JOIN、GROUP BY、ORDER BY的字段:B+树索引本身是有序的,可以减少排序和分组的开销。
- 组合查询中多个字段一起使用的情况:可使用联合查询。
不建议建立索引的情况:
- 低基数字段(重复值多):如性别字段,只有“男女”,即使建了索引也几乎没有过滤效果。
- 很少出现在查询条件中的字段:如备注、描述字段等。
- 数据量小的表:MySQL优化器判断全表扫描更快时,索引反而多余。
- 频繁更新的字段:例如余额或积分,这类字段的频繁更新会导致索引频繁维护,得不偿失。
8. 最左匹配是什么,举个例子?
最左匹配原则是指在使用联合索引进行查询时,查询条件必须包含索引中从左往右最前面的字段,且必须是连续的字段,索引才会生效。
比如:联合索引底层是按 (name, age, gender) 组成的 复合键值,并存储在一棵有序的 B+ 树中。在 B+ 树中,联合索引会把多个字段拼成一个复合键 (name, age, gender) 排序。查找时必须从最左边的字段开始连续使用字段条件,才能充分利用 B+ 树的“有序性”进行范围查找或定位,否则只能回表或全表扫。