《JAVA八股真解》六、MySQL
#JAVA##JAVA面经##JAVA内推#
1. 数据库事务的 ACID 特性
ACID 是数据库事务的四大核心特性,确保数据的一致性、可靠性和完整性。
-
原子性(Atomicity)
- 事务中的所有操作必须全部成功或全部失败。
- 若任一操作失败,整个事务将回滚至初始状态,保证数据不被破坏。
-
一致性(Consistency)
- 事务执行前后,数据库必须从一个一致状态转换到另一个一致状态。
- 满足所有完整性约束,如主键唯一、外键关联等。
-
隔离性(Isolation)
- 多个并发事务之间互不干扰,每个事务的操作与其他事务隔离。
- 通过不同的隔离级别(读未提交、读已提交、可重复读、串行化)控制并发行为。
-
持久性(Durability)
- 一旦事务提交成功,其对数据库的修改将永久保存。
- 即使系统崩溃或重启,数据也不会丢失。
总结:ACID 特性共同保障了数据库事务的可靠性与一致性,是构建稳定系统的基石。
2. MySQL 存储引擎对比
| 特性 | InnoDB | MyISAM |
|---|---|---|
| 事务支持 | 支持 | 不支持 |
| 行锁/表锁 | 行级锁 | 表级锁 |
| 外键约束 | 支持 | 不支持 |
| 崩溃恢复 | 支持(基于日志) | 不支持 |
| 索引类型 | 聚集索引(主键即索引) | 非聚集索引(独立存储) |
| MVCC支持 | 支持 | 不支持 |
说明:
- InnoDB:默认存储引擎,支持事务、行级锁、外键,适合高并发写入场景。
- MyISAM:性能较高,但不支持事务和行锁,适用于只读或读多写少的场景。
选择建议:
- 一般项目优先使用 InnoDB。
- 如果是纯查询系统且无需事务支持,可考虑 MyISAM。
3. 数据库事务隔离级别
MySQL 提供四种事务隔离级别,按严格程度递增:
| 隔离级别 | 读未提交(READ UNCOMMITTED) | 读已提交(READ COMMITTED) | 可重复读(REPEATABLE READ) | 串行化(SERIALIZABLE) |
|---|---|---|---|---|
| 脏读 | ✅ | ❌ | ❌ | ❌ |
| 不可重复读 | ✅ | ✅ | ❌ | ❌ |
| 幻读 | ✅ | ✅ | ✅ | ❌ |
解释:
- 脏读:读取未提交的数据。
- 不可重复读:同一事务中多次读取结果不一致。
- 幻读:新增或删除记录导致查询结果变化。
默认隔离级别:InnoDB 默认为
REPEATABLE READ,MyISAM 不支持事务,因此无此概念。
生产环境建议:
- 通常使用
READ COMMITTED或REPEATABLE READ。 SERIALIZABLE性能较差,仅在极端一致性要求下使用。
4. 索引的类型(种类)
MySQL 中常见的索引类型包括:
-
普通索引(Normal Index):
- 最基本的索引,允许重复值。
- 用于加速查询,但无唯一性约束。
-
唯一索引(Unique Index):
- 索引列值必须唯一,不允许重复。
- 常用于邮箱、手机号等字段。
-
主键索引(Primary Key Index):
- 一种特殊的唯一索引,不允许 NULL。
- 每张表只能有一个主键索引。
-
组合索引(Composite Index):
- 在多个列上创建的索引,提高多条件查询效率。
- 遵循“最左前缀原则”。
-
全文索引(Full-text Index):
- 用于文本内容的模糊搜索,如搜索引擎。
- 仅支持
MyISAM和InnoDB(5.6+)。
-
空间索引(Spatial Index):
- 用于地理空间数据,如经纬度坐标。
注意:合理使用索引可以大幅提升查询性能,但过多索引会影响写入性能。
5. [SQL] 索引失效的常见情况有哪些?
以下是可能导致索引失效的典型场景:
1. 使用函数或表达式
SELECT * FROM `stu` WHERE age + 10 > 30;
原因:对字段进行计算,无法直接匹配索引。
2. 使用隐式类型转换
SELECT * FROM `user` WHERE LEFT(date, 4) = '1998';
原因:字符串截取后比较,无法利用索引。
3. 使用 % 开头的 LIKE 查询
SELECT * FROM `name` WHERE name LIKE '%abc';
原因:前导通配符无法使用索引,需全表扫描。
4. 字符串与数字比较不匹配
CREATE TABLE t (a char(10));
INSERT INTO t VALUES ('1');
SELECT * FROM t WHERE a = 1; -- 不走索引
原因:隐式类型转换导致索引失效。
5. OR 条件混合使用
SELECT * FROM dept WHERE name='xxx' OR loc='xx' OR deptno = 45;
原因:若其中一个条件无法走索引,则整体可能不走索引。
6. 正则表达式不使用索引
SELECT * FROM user WHERE name REGEXP '^abc';
原因:正则表达式通常不走索引。
6. [MySQL] 索引底层原理
MySQL 的索引底层结构主要基于 B+ 树。
B+ 树特点:
- 非叶子节点只存储键值,不存储数据,减少磁盘 I/O。
- 所有叶子节点形成有序链表,便于范围查询。
- 叶子节点存储完整数据,支持快速定位。
优势:
- 支持高效范围查询。
- 减少磁盘访问次数。
- 适合大数据量场景。
7. 聚集索引与非聚集索引
InnoDB 存储引擎:
- 聚集索引:主键即为聚集索引,数据物理存储顺序与主键一致。
- 非聚集索引:额外创建的索引,指向聚集索引的主键值。
示例:
-- 主键为 id,自动创建聚集索引
CREATE TABLE user (
id INT PRIMARY KEY,
name VARCHAR(50),
INDEX idx_name (name)
);
查询过程:
- 通过
name索引找到对应主键。 - 再通过主键查找完整数据(回表)。
优化建议:
- 尽量避免频繁回表,可通过覆盖索引优化。
8. MySQL 回表查询
当查询字段不在索引中时,需要先通过索引定位主键,再根据主键回表获取其他字段,称为“回表查询”。
示例:
SELECT * FROM t WHERE name = 'lisi';
执行流程:
- 使用
name索引找到主键。 - 回表查询完整行数据。
优化方案:
- 创建覆盖索引,包含所需字段,避免回表。
9. MySQL 最左匹配原则
联合索引遵循“最左前缀”原则,查询条件必须从最左边开始匹配。
示例:
CREATE INDEX idx_ab ON table(a, b);
以下查询可以使用索引:
SELECT * FROM table WHERE a = ?;
SELECT * FROM table WHERE a = ? AND b = ?;
SELECT * FROM table WHERE a = ? AND b = ? AND c = ?;
以下查询不能使用索引:
SELECT * FROM table WHERE b = ?; -- 无法使用索引
SELECT * FROM table WHERE b = ? AND a = ?; -- 无法使用索引
提示:合理设计联合索引顺序,提升查询效率。
10. count(*)、count(1)、count(字段) 的区别?
| 方法 | 是否统计空值 | 是否统计 NULL | 是否统计所有行 |
|---|---|---|---|
count(*) |
✅ | ✅ | ✅ |
count(1) |
✅ | ✅ | ✅ |
count(字段) |
❌ | ❌ | ❌ |
详细说明:
count(*):统计所有行数,最快,推荐使用。count(1):效果同count(*),但略慢(需计算常量)。count(字段):只统计该字段非空的行数,若字段允许 NULL,则会忽略 NULL 值。
本专栏在精不在多,内容分为八股文、大厂真实面经,面试通过后将offer和面试题私发给我,可退还专栏的收益部分费用。欢迎大家共建专栏
查看8道真题和解析