☰
Java后端面试MySQL核心考点:索引、事务、锁与SQL优化全解析
2026/10/17 20:38:04 网站建设 项目流程

8 月这个时间点,很多同学都在集中准备 Java 后端面试,MySQL 往往是复习计划里最容易“背了忘、忘了背”的一块。网上的 MySQL 面试题零零散散,要么只有结论没有原理,要么全是“八股文”式的背诵清单,一旦面试官追问“为什么”,很容易卡壳。本文打算换一种复习方式,不再单独罗列面试题,而是按面试官追问的主线,把 MySQL 高频考点拆成一条完整链路:存储引擎、索引、事务、锁、SQL 优化、慢查询,最后再给一份可以直接背的高频问答和避坑清单。

如果你是正在准备 Java 面试的求职者,或者已经复习过一轮但知识点比较散,想系统串一遍 MySQL 核心内容,这篇文章可以帮你节省不少时间。读完以后,你不只是记住几个面试题答案,还能理解“一条 SQL 为什么走索引”“RR 隔离级别为什么能解决幻读”“慢查询该怎么排查”这类底层逻辑。

1. 为什么 Java 面试绕不开 MySQL

1.1 MySQL 在后端技术栈中的位置

大多数 Java 后端项目,关系型数据库选型就是 MySQL,这一点在中小型公司、互联网初创团队甚至部分大型系统里都非常常见。业务数据、订单记录、用户信息、配置数据,几乎都落在 MySQL 里。面试官考察数据库能力时,自然优先从 MySQL 入手。

MySQL 面试题不是单纯考“你会不会写 SQL”,而是通过一系列问题判断你对数据存储、并发控制、查询优化的理解深度。比如,同样问“为什么用 B+ 树”,有人只回答“查询快”,有人能从磁盘 IO、树高、范围查询、聚簇索引多个角度展开,两者在面试官心中的印象完全不同。

1.2 面试官到底想通过 MySQL 问出什么

可以把 MySQL 考察内容分成四个层次:

第一个层次:SQL 基础是否熟练。增删改查、聚合查询、多表连接、子查询、分组排序,这些是最基本的能力。

第二个层次:建表建模能力和查询优化意识。会不会设计合理的表结构、能不能根据查询场景建索引、有没有看过执行计划。

第三个层次:并发与事务理解。事务隔离级别、脏读、不可重复读、幻读、MVCC、锁机制,这些是 Java 后端面试的高频区,也是区分度最大的部分。

第四个层次:高可用与分布式扩展。主从复制、分库分表、读写分离、binlog 应用,这一类通常在中高级岗位或项目深挖环节出现。

对大多数 Java 后端岗位,第一到第三层次属于必问范围。本文重点覆盖前三个层次,并在高频题库里补充第四个层次的基础概念,方便你应对不同面试风格。

1.3 复习主线:从一条 SQL 的执行过程开始

MySQL 面试题看起来很多,但核心知识点之间其实是互相串联的。最好的复习方式,是围绕“一条 SQL 从客户端发出到存储引擎返回结果”这条主链路展开。

这条链路上,你会遇到连接器、分析器、优化器、执行器;会碰到存储引擎为什么要区分 InnoDB 和 MyISAM;会走进索引,理解 B+ 树为什么高效;会进入事务,理解隔离级别和 MVCC;会接触锁,理解并发控制;最后还要掌握慢查询和 Explain,用来排查性能问题。整篇文章就是按这条主线设计的。

2. 环境准备:本地搭一套可复现的 MySQL 练习环境

面试准备不能只看文章,最好在本地准备好一套 MySQL 练习环境,把索引失效、事务隔离级别、死锁、慢查询这些场景亲手跑一遍。这样印象更深,面试时也能说出“我复现过”的细节。

2.1 安装 MySQL:推荐使用 Docker

本地安装 MySQL 有很多方式,最省心的是用 Docker。一条命令即可启动一个 MySQL 8.x 实例,用完可以随时删掉重建,不影响本机环境。

docker run -d \ --name mysql8 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORD=123456 \ mysql:8.0

启动后,进入容器连接到 MySQL:

docker exec -it mysql8 mysql -uroot -p123456

需要注意几点:

  • MySQL 8.x 默认认证插件是 caching_sha2_password,如果项目里用 Java 连接,建议使用 mysql-connector-j 8.x 版本驱动,避免出现认证协议不兼容的报错。
  • 如果同时跑多个 MySQL 实例,记得修改端口,避免 3306 冲突。
  • 生产环境不要直接用简单密码,本地测试无所谓。
  • 如果你已经在 Windows 或 Linux 上安装过 MySQL,完全可以直接用本地环境,命令和 SQL 都兼容。

版本说明:本文章的 SQL 示例基于 MySQL 8.x 编写,MySQL 5.7 大部分也适用,但个别功能存在差异,请以你的实际环境为准。

2.2 准备示例表

为了验证索引和事务,建议建两张简单的业务表:用户表和订单表。

CREATE DATABASE IF NOT EXISTS interview_demo DEFAULT CHARSET utf8mb4; USE interview_demo; CREATE TABLE `user` ( `id` INT NOT NULL AUTO_INCREMENT, `name` VARCHAR(50) NOT NULL DEFAULT '', `age` INT NOT NULL DEFAULT 0, `city` VARCHAR(50) NOT NULL DEFAULT '', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `order` ( `id` INT NOT NULL AUTO_INCREMENT, `user_id` INT NOT NULL DEFAULT 0, `amount` DECIMAL(10,2) NOT NULL DEFAULT 0, `status` TINYINT NOT NULL DEFAULT 0 COMMENT '0待支付 1已支付 2已取消', `create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这两张表结构很简单,但足够演示索引、连接查询、事务、Explain 等场景。你可以根据自己的需求继续插入测试数据。

2.3 开启慢查询日志

面试中经常问“慢查询怎么排查”,本地环境可以提前把慢查询日志打开。

SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;

这两条命令的含义是:开启慢查询日志,执行时间超过 1 秒的 SQL 会被记录下来。long_query_time 的默认值通常是 10 秒,排查问题时可以调低。

生产环境不建议随意开启慢查询日志,因为会增加磁盘 IO 和性能开销。本地测试环境可以放心使用。

3. SQL 执行过程与存储引擎

3.1 一条查询 SQL 的执行链路

面试官经常问:“一条 select 语句在 MySQL 中是怎么执行的?”这个问题看起来简单,但能回答完整的人并不多。标准的执行链路可以分为以下几步:

  1. 客户端通过网络协议将 SQL 发给 MySQL 服务器。
  2. 连接器负责建立连接、校验用户名密码、获取权限信息。
  3. 如果开启查询缓存且命中缓存,MySQL 8.0 之前会直接返回结果,MySQL 8.0 开始已经移除查询缓存。
  4. 分析器对 SQL 做词法分析和语法分析,检查 SQL 是否符合语法规则。
  5. 优化器决定使用哪个索引、以什么顺序连接表,生成执行计划。
  6. 执行器调用存储引擎接口,逐行读取、判断并返回结果。

这个链路对应了不少面试题,比如“分析器做了什么”“优化器怎么选索引”“执行器和存储引擎是什么关系”。能把这个流程讲清楚,说明你不只是会写 SQL,而是理解 MySQL 的整体架构。

3.2 InnoDB 与 MyISAM 对比

存储引擎是 MySQL 面试的基础题。面试中最常对比的是 InnoDB 和 MyISAM。

对比项InnoDBMyISAM
事务支持支持 ACID 事务不支持事务
锁粒度支持行锁,并发能力强只支持表锁
外键约束支持外键不支持外键
崩溃恢复支持,通过 redo log 恢复崩溃后恢复能力较弱
聚簇索引是,主键索引叶子节点存整行数据不是,索引文件和数据文件分离
全文索引MySQL 5.6 之后支持原生支持
适用场景大多数业务系统,尤其需要事务和高并发写入只读、数据仓库类场景

这里有一个高频追问:为什么 InnoDB 适合高并发?核心原因是行锁。MyISAM 使用表锁,写一条记录也会锁住整张表,写入性能在并发场景下很差;InnoDB 支持行级锁,多个事务操作不同记录时互不阻塞,并发能力更强。加上事务、崩溃恢复等能力,InnoDB 成为 MySQL 默认存储引擎是很自然的选择。

3.3 存储引擎选择建议

新项目默认选择 InnoDB 基本没有争议。即使在读多写少的场景,也优先考虑用 InnoDB + 缓存方案,而不是退回 MyISAM。MyISAM 在只读报表、日志分析这类对事务没要求、写入很少的场景中还有一定使用空间,但实际业务系统已经很少首选它。

如果你在建表时没有显式指定存储引擎,MySQL 8.x 默认就是 InnoDB。这也是面试中一个基础得分点。

4. 索引为什么能加速:B+ Tree 与聚簇索引

4.1 没有索引时 MySQL 怎么查

假设 user 表有 100 万条数据,现在要查 name = '张三' 的记录。如果没有索引,MySQL 只能从第一行开始,逐行扫描整张表,把每一条记录的 name 都取出来比较一次。这个操作叫全表扫描,数据量越大,耗时越长。

索引的本质,就是为数据额外建立一种有序的查找结构。通过索引,MySQL 可以快速定位到目标数据所在位置,避免全表扫描。但索引不是免费的,它需要额外的存储空间,写入数据时还需要维护索引结构,所以索引不是建得越多越好。

4.2 为什么 InnoDB 选择 B+ Tree

InnoDB 的索引结构是 B+ Tree。要理解 B+ Tree 为什么高效,可以先看几个备选方案:

  • Hash 索引:等值查询非常快,但不支持范围查询,也无法利用索引排序。哈希冲突多时性能也不稳定。
  • 红黑树:平衡二叉树在内存中查找很快,但树的高度较高。数据量大时,每次从磁盘读取一个节点都要一次 IO,树越高 IO 次数越多。
  • B-Tree:每个节点可以存储多个键,树更矮,但仍然在非叶子节点保存数据,导致单次 IO 能加载的键数量变少。
  • B+ Tree:非叶子节点只存索引键,不存数据,所以单个节点能存放更多键,树更加矮胖;叶子节点按顺序排列并通过链表连接,支持高效的范围查询。

B+ Tree 牺牲了非叶子节点直接访问数据的特性,换来了更低的树高和更强的范围查询能力。一次磁盘 IO 通常能读取一个页,页大小默认 16KB,非叶子节点只存键值可以大幅减少 IO 次数,这就是 B+ Tree 成为 InnoDB 索引核心结构的原因。

4.3 聚簇索引、二级索引、回表、覆盖索引

InnoDB 的索引按照存储结构,可以分成两类:

聚簇索引,也叫主键索引。InnoDB 中聚簇索引的叶子节点直接存储整行数据。如果你定义了主键,主键索引就是聚簇索引;如果没有主键,InnoDB 会选择一个唯一非空索引作为聚簇索引;如果还不行,会生成隐藏主键。

二级索引,也叫非聚簇索引、辅助索引。二级索引的叶子节点存储的是主键值。比如在 name 字段上建立索引,索引叶子节点保存的是对应行的主键 id。

由于二级索引只存主键值,当你通过 name 索引查到主键 id 后,还想获取完整行数据,就需要再回到聚簇索引里查一次,这个动作称为回表。

SELECT * FROM user WHERE name = '张三';

如果 name 上有二级索引,上面的 SQL 会先通过 name 索引找到主键 id,再通过主键 id 回到聚簇索引查整行数据,这就是一次回表。

覆盖索引指的是,查询字段全部包含在某个二级索引中,不需要再回表。比如:

SELECT id, name FROM user WHERE name = '张三';

如果 name 索引的叶子节点存了主键 id,那么 id 和 name 都能直接从二级索引中获得,不需要回表,Extra 列会显示 Using index。

4.4 联合索引与最左前缀原则

联合索引也叫多列索引,比如在 (city, age) 两个字段上建索引。面试常考“最左前缀原则”:联合索引在查询时,必须从最左边的列开始匹配,不能跳过。

CREATE INDEX idx_city_age ON user(city, age);

以下查询能用到这个联合索引:

SELECT * FROM user WHERE city = '上海' AND age = 25; SELECT * FROM user WHERE city = '上海';

以下查询无法用到联合索引:

SELECT * FROM user WHERE age = 25;

因为 age 不是联合索引的最左列,查询时无法从索引的第一个字段开始匹配。不过要注意,是否一定走索引,最终还是由优化器根据数据量和成本决定。

4.5 常见索引失效场景

面试经常问“哪些情况会导致索引失效”,但很多答案过于绝对,实际需要结合数据量和优化器判断。常见的典型场景有:

  • 对索引列使用函数,比如 WHERE YEAR(create_time) = 2024,如果 create_time 是索引列,函数会导致索引失效。
  • 隐式类型转换,比如索引列是 varchar,查询条件用了数字,MySQL 可能无法使用索引。
  • LIKE 以 % 开头,比如 WHERE name LIKE '%张%',因为无法确定前缀,难以走索引。
  • OR 连接非索引列,比如 WHERE id = 1 OR age = 20,如果 age 没有索引,可能直接全表扫描。
  • 不满足最左前缀原则。

需要记住,索引失效不是绝对的,优化器会评估成本。面试时主动说清楚这一点,会显得更专业。

5. 事务隔离级别与 MVCC

5.1 ACID 是什么

事务是数据库操作的最小逻辑单元,要么全部成功,要么全部失败。MySQL InnoDB 事务满足 ACID 四个特性:

  • 原子性:事务中的操作要么全部完成,要么全部回滚。InnoDB 通过 undo log 实现回滚。
  • 一致性:事务执行前后,数据完整性不能被破坏。一致性是数据库整体目标,由应用层和数据库共同保证。
  • 隔离性:多个事务并发执行时,应该像串行执行一样互不干扰。隔离性由锁和 MVCC 实现。
  • 持久性:事务提交后,数据变更要永久保存,即使系统崩溃。InnoDB 通过 redo log 保证持久性。

面试问答中,如果只背 ACID 含义,只能算及格。能进一步说出 undo log 与原子性的关系、redo log 与持久性的关系,才是加分项。

5.2 并发事务带来的三个问题

多个事务并发执行时,容易出现以下几类数据问题。

脏读:一个事务读到了另一个事务未提交的数据。比如事务 A 修改了一行数据但还没提交,事务 B 读取了这行数据,随后事务 A 回滚,事务 B 读到的就是无效数据。

不可重复读:同一个事务内,两次读取同一行数据,结果不一致。因为其他事务在这期间提交了修改。

幻读:同一个事务内,两次执行相同的查询,返回的结果集条数发生了变化。比如事务 A 查询某条件下的记录只有 5 条,事务 B 插入了一条新记录并提交,事务 A 再次查询变成了 6 条,多出来的一行就是“幻行”。

这三个问题容易混淆,面试时可以用一个简短例子说明,避免只背定义。

5.3 四个隔离级别

SQL 标准定义了四个隔离级别,MySQL InnoDB 默认使用可重复读 REPEATABLE READ。

隔离级别脏读不可重复读幻读
READ UNCOMMITTED 读未提交可能可能可能
READ COMMITTED 读已提交不可能可能可能
REPEATABLE READ 可重复读不可能不可能可能,但 InnoDB 通过 MVCC 和间隙锁解决
SERIALIZABLE 串行化不可能不可能不可能

读未提交隔离级别下,事务可以读到其他事务未提交的数据,容易产生脏读,实际业务很少使用。串行化隔离级别下,事务完全串行执行,性能很低,只在极端需要强一致的场景使用。

MySQL 默认的可重复读隔离级别,在快照读场景下通过 MVCC 解决不可重复读和幻读,在当前读场景下通过间隙锁解决幻读,这一点是面试核心,面试官很容易追问。

5.4 MVCC 核心原理

MVCC 的中文意思是多版本并发控制。简单理解,就是让快照读不需要加锁,通过数据行的“多个版本”实现一致性读取。

InnoDB 的每行数据除了业务字段,还有几个隐藏字段:

  • DB_TRX_ID:最后修改或插入这行数据的事务 ID。
  • DB_ROLL_PTR:回滚指针,指向 undo log 中的上一个版本。
  • 隐藏主键等。

每次事务更新一行数据时,InnoDB 不会直接覆盖旧值,而是把旧值写入 undo log,形成一条版本链。新读取一个事务时,会根据 ReadView 判断当前事务应该看到版本链上的哪个版本。

ReadView 可以理解成“事务快照”,里面记录了当前活跃事务列表等信息。当一个事务读取数据时,MySQL 会沿着 undo log 版本链查找,找到符合可见性规则的第一个版本。

这里有一个重要区别:

  • 在 READ COMMITTED 隔离级别下,每次快照读都会生成新的 ReadView,所以其他事务提交后,当前事务再次读取可以看到新数据,出现不可重复读。
  • 在 REPEATABLE READ 隔离级别下,事务内第一次快照读时生成 ReadView,后续快照读复用同一个 ReadView。其他事务提交的新版本对于当前事务不可见,因此解决了不可重复读。

MVCC 解决的是快照读场景下的幻读。对于当前读场景,比如 SELECT ... FOR UPDATE、UPDATE、DELETE,MySQL 通过间隙锁或临键锁来限制其他事务插入新记录,从而解决幻读。这也是面试中最容易出彩的点。

6. 锁机制与死锁排查

6.1 行锁与表锁

InnoDB 默认使用行级锁,表级锁也可以在特定场景出现,比如 DDL 语句或者查询没有走索引时。

行锁是加在索引记录上的,所以如果一条 update 语句的 where 条件没有走索引,InnoDB 无法确定具体行,就可能锁住更多记录,甚至升级为表锁。这会导致并发性能急剧下降,是生产中常见的性能隐患。

基本的行锁有两种模式:

  • 共享锁,也叫读锁。多个事务可以同时持有共享锁,但都不能修改数据。使用 SELECT ... LOCK IN SHARE MODE 或 SELECT ... FOR SHARE 加锁。
  • 排他锁,也叫写锁。一个事务持有排他锁后,其他事务不能加共享锁和排他锁。INSERT、UPDATE、DELETE 默认加排他锁;SELECT ... FOR UPDATE 可以手动加排他锁。

面试时,尽量用自己的话说清楚:共享锁就是“大家可以一起读,但谁都不能写”,排他锁就是“只有我能读写,你们都不许动”。

6.2 间隙锁与临键锁

在 REPEATABLE READ 隔离级别下,InnoDB 为了解决当前读的幻读问题,引入了间隙锁和临键锁。

间隙锁锁住的是一个范围区间,而不是具体的记录。比如表中 id 有 1、5、10,间隙锁可能锁住 (1,5) 这个区间,这样其他事务就无法在这个区间插入 id=3 的记录,自然就不会出现幻读。

临键锁是记录锁和间隙锁的组合,锁住的是一段左开右闭的区间,比如 (1,5],既锁住记录,又锁住记录前面的间隙。

要注意,间隙锁会降低并发性能,只在 REPEATABLE READ 及以上隔离级别生效。如果把隔离级别改成 READ COMMITTED,间隙锁通常会失效,MySQL 会使用其他机制控制并发。

6.3 悲观锁与乐观锁

面试中,锁机制经常和“悲观锁、乐观锁”一起考。悲观锁在操作数据前先加锁,认为别人一定会修改数据;乐观锁则默认别人不会修改,更新时再检查版本。

悲观锁在 MySQL 中通过 SELECT ... FOR UPDATE 实现,事务结束自动释放。使用时要特别注意,加锁的查询条件必须走索引,否则可能锁范围过大。

乐观锁通常加一个 version 版本号字段,更新时比较版本号:

UPDATE user SET age = 26, version = version + 1 WHERE id = 1 AND version = 5;

影响行数为 0 说明版本号不匹配,更新失败,由业务层重试或提示用户。

6.4 死锁怎么排查

死锁是指两个或多个事务互相等待对方持有的锁,导致事务无法继续执行。InnoDB 会自动检测死锁,并将一个事务回滚,让另一个事务继续执行。

面试中经常问“死锁怎么排查”。常见思路是:

  1. 查看最近一次死锁信息:在 MySQL 命令行执行 SHOW ENGINE INNODB STATUS,重点看 LATEST DETECTED DEADLOCK 部分。
  2. 从输出中看两条事务各自持有什么锁、等待什么锁。
  3. 找到死锁的根源,通常是两个事务以不同顺序获取资源。

比如事务 A 先更新 id=1 再更新 id=2,事务 B 先更新 id=2 再更新 id=1,两者就可能在 id=1 和 id=2 上互相等待。

解决死锁的常见手段包括:统一加锁顺序、缩小事务执行时间、减少大事务、让查询尽量走索引避免锁范围过大。

7. SQL 优化与慢查询分析

7.1 开启慢查询日志定位问题 SQL

项目上线后出现接口变慢,优先怀疑数据库慢查询。慢查询日志就是用来记录执行时间超过阈值的 SQL。

在 MySQL 命令行中执行:

SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; SHOW VARIABLES LIKE 'slow_query_log';

也可以写入配置文件,永久生效:

[mysqld] slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 1 log_queries_not_using_indexes = 1

log_queries_not_using_indexes 表示把未使用索引的查询也记录到慢查询日志,适合用来发现大量全表扫描 SQL。

慢查询日志文件可以使用 mysqldumpslow 工具分析:

mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

这条命令的意思是:按查询耗时排序,显示耗时最长的前 10 条 SQL。

7.2 使用 Explain 分析执行计划

慢查询日志只是发现问题的入口,定位到具体 SQL 后,需要分析它为什么慢。最常用的方法是在 SQL 前面加 EXPLAIN。

EXPLAIN SELECT * FROM `order` WHERE user_id = 123;

执行结果会展示这条 SQL 的执行计划,重点关注几个字段:

字段含义
type访问类型,从好到差依次是 system、const、eq_ref、ref、range、index、ALL
possible_keys可能用到的索引
key实际使用的索引
rows预估扫描行数
Extra额外信息,比如 Using index、Using where、Using temporary、Using filesort

type 字段是重要参考。ALL 表示全表扫描,index 表示扫描了整个索引树,range 表示范围扫描,ref 表示通过索引等值查询。type 为 ALL 或 index 的 SQL 通常是优化重点。

Extra 字段中,如果出现 Using filesort,说明 SQL 需要额外的排序操作,可能是 order by 的字段没有走索引;如果出现 Using temporary,说明查询过程中使用了临时表,常见于 group by、distinct 或大数据量排序。

7.3 一个优化实战示例

假设发现一条慢查询:

SELECT * FROM `order` WHERE user_id = 123 ORDER BY create_time DESC LIMIT 20;

如果 order 表只有主键索引,这条 SQL 的执行过程很可能是:先通过 user_id 全表扫描,找到所有该用户的订单,再对 create_time 排序,最后取前 20 条。数据量大时,排序成本很高。

优化方式:建立一个联合索引。

ALTER TABLE `order` ADD INDEX idx_user_create (user_id, create_time);

加上索引后,InnoDB 可以直接通过联合索引定位 user_id=123 的记录,而且 create_time 天然有序,不需要额外 filesort,性能明显提升。

这条优化思路面试中经常考,核心就是:索引不光能加速 where 过滤,还能让 order by 利用索引有序性,避免排序。

再补充几个常见优化点:

  • 避免 SELECT *,只查需要的字段,减少回表和网络传输。
  • 分页查询使用 LIMIT 时,深分页可能很慢,比如 LIMIT 100000, 20,可以通过子查询或记录上次最后一条 id 来优化。
  • 对频繁使用的查询条件,合理设计联合索引,避免为每个字段单独建索引。

8. 高频 MySQL 面试题整理

这一节把 Java 后端面试中最高频的 MySQL 面试题按模块整理出来,每道题给出回答思路和核心得分点。建议先自己说一遍答案,再看参考思路,效果更好。

8.1 基础与 SQL 类

  1. 一条 select 语句的执行过程?

参考答案:客户端连接 MySQL 后,SQL 依次经过连接器、分析器、优化器、执行器,最终调用存储引擎读取数据。MySQL 8.0 之前还有查询缓存,8.0 之后已移除。

得分点:能说出分析器负责词法语法分析,优化器负责选索引和决定连接顺序,执行器负责调用存储引擎接口。

  1. truncate delete drop 有什么区别?

参考答案:DELETE 是 DML,可以带 WHERE,逐行删除,不释放表空间;TRUNCATE 是 DDL,清空整张表并释放存储空间,不能加 WHERE;DROP 是 DDL,直接删除表结构。二者都可以手动删除数据,但 DDL 操作隐式提交,不可回滚。

得分点:事务中 DELETE 可以回滚,TRUNCATE 不支持;说到“隐式提交”会加分。

  1. WHERE 和 HAVING 有什么区别?

参考答案:WHERE 在分组之前过滤,不能使用聚合函数;HAVING 在分组之后过滤,可以使用聚合函数。WHERE 过滤条件不参与分组,HAVING 通常和 GROUP BY 配合使用。

  1. 内连接、左连接、右连接的区别?

参考答案:内连接只返回两边都匹配的行;左连接返回左表全部行,右表没有匹配项时用 NULL 填充;右连接相反。实际项目中左连接最常见。

得分点:能补充连接查询的执行顺序,先笛卡尔积再过滤,或者提到小表驱动大表的优化思想。

  1. 什么是存储过程?优缺点是什么?

参考答案:存储过程是预编译的 SQL 集合,可以封装复杂业务逻辑,减少网络传输,但数据库层承担业务逻辑会导致维护困难、不好调试。

得分点:指出在互联网项目中不推荐大量使用存储过程,业务逻辑尽量放在应用层。

8.2 索引与 SQL 优化类

  1. 为什么 InnoDB 使用 B+ 树做索引?

参考答案:B+ 树非叶子节点只存索引键,树更矮,减少磁盘 IO;叶子节点通过链表连接,范围查询高效;叶子节点存主键值,适合聚簇索引和二级索引结构。

得分点:能对比 B-Tree、Hash、红黑树的适用场景。

  1. 什么是回表?如何避免回表?

参考答案:二级索引查到主键后,再到聚簇索引查整行数据,就是回表。避免回表的方法是覆盖索引,也就是查询字段全部在二级索引中。

得分点:能说清楚覆盖索引的 Extra 是 Using index。

  1. 联合索引的最左前缀原则是什么?

参考答案:联合索引按最左边字段开始匹配,查询条件必须包含最左边的列才能用索引。索引字段顺序设计要结合实际查询频率。

得分点:能解释为什么 MySQL 不直接跳过最左列使用索引。

  1. 什么情况下索引会失效?

参考答案:对索引列使用函数、隐式类型转换、LIKE 以 % 开头、OR 连接非索引列、不满足最左前缀原则等,都可能让索引失效。最终是否失效,要看优化器对成本的判断。

得分点:不把结论说死,强调优化器会评估数据量和执行成本。

  1. 如何优化一条慢查询 SQL?

参考答案:先用 EXPLAIN 查看执行计划,重点看 type、key、rows、Extra;再检查是否有全表扫描、filesort、临时表;根据查询条件建立合适的联合索引;避免 SELECT *;必要时改写 SQL。

得分点:回答里提到慢查询日志定位问题 SQL,再用 EXPLAIN 分析,形成完整排查链路。

8.3 事务与锁类

  1. 事务的 ACID 分别是怎么实现的?

参考答案:原子性通过 undo log 实现回滚;持久性通过 redo log 保证崩溃恢复;隔离性通过锁和 MVCC 实现;一致性由应用约束和数据库约束共同保证。

得分点:能提到 undo log 和 redo log,而不是只背 ACID 四个单词。

  1. MySQL 默认隔离级别是什么?

参考答案:MySQL InnoDB 默认隔离级别是 REPEATABLE READ,和 Oracle 默认的 READ COMMITTED 不同。RR 下通过 MVCC 解决快照读的不可重复读和幻读,通过间隙锁解决当前读的幻读。

得分点:能和 Oracle 默认隔离级别对比,说明为什么 MySQL 选择 RR。

  1. 脏读、不可重复读、幻读有什么区别?

参考答案:脏读读到未提交数据;不可重复读是同一行数据两次读取不一致;幻读是结果集行数变化。脏读是隔离性最差的情况,幻读最难理解。

得分点:各举一个小例子,面试官会觉得理解到位。

  1. MVCC 解决了什么问题?

参考答案:MVCC 让快照读不加锁就能实现一致性读取。RR 下通过复用一个 ReadView 解决不可重复读,RC 下每次读取生成新 ReadView,会出现不可重复读。

得分点:能说到 ReadView 就是事务快照,理解版本链和可见性判断。

  1. select for update 是什么?有什么注意事项?

参考答案:它会对查询结果加排他锁,当前事务提交或回滚后释放。使用时要确保 where 条件走索引,否则可能锁过多记录,影响并发性能。

得分点:提到悲观锁,并意识到锁范围问题。

  1. 悲观锁和乐观锁怎么实现?

参考答案:悲观锁用 SELECT ... FOR UPDATE 加锁;乐观锁用版本号机制,更新时校验版本,影响行数为 0 则更新失败。

得分点:提到乐观锁适合冲突较少的场景,悲观锁适合写冲突较多的场景。

8.4 架构与部署类

  1. 主从复制是怎么实现的?

参考答案:主库把数据变更写入 binlog,从库通过 IO 线程拉取 binlog 并写入中继日志,SQL 线程再回放中继日志,实现数据同步。

得分点:能说出 binlog、中继日志、IO 线程、SQL 线程四个关键概念。

  1. 什么是读写分离?主要解决什么问题?

参考答案:读写分离让读请求走从库、写请求走主库,降低主库压力,提升读扩展能力。但主从存在延迟,读刚写入的数据可能读不到。

得分点:能主动提主从延迟问题,并能说出延迟场景可以是读不到最新数据,比如刚下单查订单列表。

  1. 分库分表了解吗?

参考答案:分库分表解决单库单表数据量过大导致的性能瓶颈,常见方式有垂直拆分和水平拆分。水平分表后,查询需要带上分片键,否则会路由到所有表,复杂度明显上升。

得分点:能说出分片键的重要性,以及分页、分布式事务、跨库 join 是主要难点。

  1. 缓存和数据库一致性怎么做?

参考答案:常见方案是先更新数据库,再删除缓存。如果缓存删除失败,可以通过消息队列重试或延迟双删兜底。不要先更新缓存,因为一旦数据库回滚,缓存已经变了。

得分点:能提到删除缓存而不是更新缓存,能提到重试机制。

9. 面试回答话术与避坑清单

9.1 回答结构:结论先行,再展开原理

MySQL 面试题很多都有标准答案,但面试官更希望听到结构清晰的表达。建议使用“结论先行 → 原理补充 → 场景举例”的结构。

比如问“为什么使用 B+ 树”,可以先说结论:为了减少磁盘 IO 并支持高效范围查询。然后展开原理:B+ 树非叶子节点不存数据,树更矮,一次查询 IO 次数更少;叶子节点链表连接,范围查询不用回上层节点。最后补一个例子:InnoDB 主键索引叶子节点存整行数据,二级索引叶子节点存主键,回表过程也是基于这个结构。

这样回答,即使不是最优答案,面试官也能清晰跟住你的思路。

9.2 面试避坑清单

准备 MySQL 面试时,有几个常见问题值得注意:

  • 只背结论,不解释原理。比如知道“RR 能解决幻读”,但说不清是 MVCC 解决快照读、间隙锁解决当前读,容易被追问卡住。
  • 把索引失效说成绝对结论。索引是否失效和优化器、数据量、索引统计信息都有关系,回答时留有余地更稳妥。
  • 混淆事务隔离级别。四个隔离级别和三个问题之间的对应关系要能快速默写。
  • 没有排查思路。问“SQL 很慢怎么办”,不要只说“加索引”,要说清楚先开慢查询日志、再用 Explain、再看执行计划结构。
  • 涉及 delete update 时安全意识不足。面试中遇到“删除数据”这类问题,要主动提到 WHERE 条件、事务回滚、备份,这会让面试官觉得你有生产环境经验。

9.3 考前最后一天怎么复习

最后一天不建议再刷大量新题,而是把核心内容过一遍,重点验证自己的表达是否流畅。

可以先对着镜子或者录屏自问几个高频题,比如“InnoDB 和 MyISAM 的区别”“一条 SQL 的执行过程”“Explain 中 type 的取值顺序”,看能不能不卡壳说出来。

然后在本地环境把索引失效场景、死锁复现、Explain 执行计划各跑一遍。比如建两张表,开两个事务交叉更新同一条记录,触发一次死锁,再用 SHOW ENGINE INNODB STATUS 查看死锁输出。这个过程比背十道题都管用。

最后翻一下自己项目里写过的复杂 SQL,想一想为什么当初要这么写,有没有优化空间。面试官问你项目经历时,大概率会顺着项目里的表结构和 SQL 继续深挖,提前准备比临场发挥更稳。

把这些步骤做完,再去面对 MySQL 面试题,你已经不是停留在背答案,而是能讲清楚原理和排查思路了。希望这篇 Java 面试 MySQL 复习笔记能帮你节省时间,少走弯路。8 月准备面试,时间不算多,但抓住重点,3 天足够把 MySQL 这条主线完整过一遍。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询