《Java 100 天进阶之路》第90篇:MyBatis面试高频真题(2026版)

📌 专栏连载《2026全新 | Java 100 天进阶之路:从零基础到上岗就业,108篇完整学习地图》
⬅️ 上一篇:第89篇:MySQL面试压轴题 |
➡️ 下一篇:第91篇:Redis核心数据结构



一、MyBatis SQL完整执行流程链路图

💡 重点:面试官问执行流程时,直接画出这张图,秒杀80%只会背文字的竞争者!

加载配置构建SqlSessionFactory

openSession获取SqlSession

getMapper生成MapperProxy代理

调用Mapper接口方法

MapperMethod分发SQL类型

Executor先查询一二级缓存

StatementHandler创建PreparedStatement

ParameterHandler填充占位符

执行JDBC查询

ResultSetHandler映射实体返回

二、基础概念篇(5道高频题)

Q1:MyBatis 是什么?它和 JDBC 有什么区别?

MyBatis 是一个半自动 ORM 框架,通过 XML 或注解配置 SQL 语句,将 Java 对象与数据库记录映射。JDBC 需要手动获取连接、创建 Statement、执行 SQL、处理结果集、关闭资源;MyBatis 封装了这些重复操作。

背诵口诀:半自动ORM写SQL,JDBC封装少写码,灵活度高好优化。

Q2:MyBatis 和 Hibernate 的区别?

对比项MyBatisHibernate
ORM类型半自动全自动
SQL控制手写SQL,灵活度高自动生成,适合简单CRUD
学习成本较低陡峭
N+1问题通过<association>/<collection>规避常见,需额外优化

面试官追加:Hibernate 的 N+1 查询问题怎么解决?(答:通过 <association><collection> 标签优化关联查询,或使用 @BatchSize

Q3:MyBatis 的核心组件有哪些?

SqlSessionFactoryBuilderSqlSessionFactorySqlSessionExecutorMappedStatementMapper

小结Configuration 存储所有配置,是 MyBatis 的“大脑”。

Q4:MyBatis 有哪些优点和缺点?

优点:SQL 与代码分离,灵活性高;支持动态 SQL;方便进行 SQL 优化。

缺点:需要手写 SQL;XML 配置较多;对数据库移植性有一定影响。

Q5:什么是 ORM?MyBatis 属于哪种 ORM?

ORM 全称 Object Relational Mapping(对象关系映射)。MyBatis 属于半自动 ORM,因为 SQL 需要开发者自己写。


三、核心SQL配置篇(8道真题)

Q6:#{}${} 的区别是什么?

对比项#{}${}
底层处理预编译占位符 → ?纯字符串替换
SQL注入✅ 防止❌ 存在风险
适用场景参数值传递动态表名/列名
推荐度优先使用谨慎使用,需白名单

⚠️ 重点:能用 #{} 的地方绝不用 ${};表名/列名动态场景只能用 ${},但需白名单校验!

Q7:MyBatis 如何防止 SQL 注入?

核心是 #{} 预编译。SQL 模板先发到数据库预编译,参数值通过占位符独立传递,不被解析为 SQL 逻辑。

面试官追加:MyBatis-Plus 的 LambdaQueryWrapper 如何防注入?(答:使用 Lambda 表达式封装字段名,避免字符串拼接)。

Q8:动态 SQL 有哪些标签?执行原理是什么?

包括 <if><choose>/<when>/<otherwise><where><set><foreach><trim><bind>。原理是根据 OGNL 表达式动态拼接 SQL。

Q9:<foreach> 标签的用法?

用于遍历集合,常见于批量插入或 IN 查询。

  • ⚠️ 重点:使用 ExecutorType.BATCH 批量提交性能更佳,注意 MySQL max_allowed_packet 参数限制。

Q10:<bind> 标签的作用是什么?

从 OGNL 表达式中创建变量并绑定到上下文。常用于模糊查询拼接 %,避免在业务代码中硬编码。

Q11:实体类属性名和表字段名不一致怎么办?

方案一:resultMap 手动映射;方案二:开启驼峰命名转换;方案三:使用 @Results 注解。

Q12:resultTyperesultMap 的区别?

resultType 要求列名与属性名一致,自动映射;resultMap 支持自定义映射,处理复杂关联。

Q13:MyBatis 分页如何实现?

方案一:SQL 手写 LIMIT;方案二:PageHelper 分页插件(底层拦截 Executor.query() 自动拼接 LIMIT)。


四、Mapper动态代理源码篇(5题)

Q14:Mapper 接口为什么不需要实现类?

MyBatis 使用 JDK 动态代理。运行时生成 MapperProxy 代理对象,拦截接口方法,转而执行 MappedStatement 代表的 SQL。

背诵口诀:JDK代理生成Proxy,拦截方法找SQL。

Q15:Mapper 接口方法能重载吗?

不能。MyBatis 使用 全限定名 + 方法名 作为唯一标识,重载会导致映射冲突。

Q16:MyBatis 执行 SQL 的完整流程?

(参见文章开头完整链路图)读取配置 → 创建 SqlSession → Mapper代理调用 → Executor执行 → 参数处理 → 结果映射 → 返回。

Q17:MyBatis 的 Executor 有哪些?

执行器特点适用场景
SimpleExecutor每次创建新Statement默认,通用
ReuseExecutor复用Statement减少创建开销
BatchExecutor批量执行批量操作
CachingExecutor装饰器包装开启二级缓存时

面试官追加:开启二级缓存时用什么 Executor?(答:CachingExecutor,装饰器模式包装基础执行器)

Q18:MyBatis 插件(Interceptor)的原理?

拦截四大组件(ExecutorStatementHandlerParameterHandlerResultSetHandler)的方法,通过 InterceptorChain 形成责任链


五、缓存机制篇(5题)

Q19:MyBatis 的一级缓存和二级缓存的区别?

对比项一级缓存二级缓存
作用范围SqlSession 级别Mapper(Namespace)级别
默认状态默认开启需手动配置
生命周期会话关闭即销毁跨SqlSession共享
实现方式基于HashMap本地缓存需配置<cache/>

Q20:一级缓存失效的场景?

  1. 不同 SqlSession;2. 执行增删改操作;3. 手动 clearCache();4. 事务提交/回滚;5. SqlSession 关闭。

Q21:二级缓存如何配置?

Mapper XML 添加 <cache/> 标签,实体类实现 Serializable

Q22:生产环境为什么建议禁用二级缓存?

⚠️ 重点:在分布式微服务架构下,MyBatis 原生二级缓存基于本地内存,多节点部署极易导致数据不一致。生产环境标准做法:直接禁用,转而使用 Redis 等分布式缓存!若需本地加速,推荐 Spring Cache + Caffeine

Q23:二级缓存脏读问题如何解决?

多表关联更新不会自动清空其他表的缓存。解决:关联表缓存在同一 namespace;或使用 cache-ref;或多表查询禁用二级缓存。

💬 互动思考:你们项目是否踩过 MyBatis 二级缓存脏读问题?生产是如何解决的?评论区交流方案!


六、Spring整合篇(3题)

Q24:Spring 如何整合 MyBatis?

SqlSessionFactoryBean 创建工厂;@MapperScan 扫描接口注册为 MapperFactoryBeanSqlSessionTemplate 管理生命周期。

Q25:@MapperScan 注解的原理?

@Import(MapperScannerRegistrar.class),启动时扫描指定包,将 Mapper 接口注册为 MapperFactoryBean

Q26:Spring 整合后 Mapper 注入的是什么对象?

注入的是 JDK 动态代理对象MapperProxy)。


七、MyBatis-Plus全考点(6题)

Q27:MyBatis-Plus 是什么?

MyBatis 的增强工具,只做增强不做改变。MP = MyBatis + 通用 CRUD + 条件构造 + 内置插件。

Q28:MyBatis-Plus 的核心组件有哪些?

BaseMapperIService/ServiceImplWrapper(条件构造器);Plugin(分页、乐观锁等);SqlInjector

Q29:MP 如何在不修改 MyBatis 源码的前提下实现通用 CRUD?

依靠自动配置类 MybatisPlusAutoConfiguration 扩展 MyBatis 原生机制,无侵入改造:

  1. Spring Boot 启动时自动注入 MybatisSqlSessionFactoryBean 替代原生工厂 Bean
  2. MapperRegistry 初始化阶段,通过 AbstractSqlInjector 动态生成 insertselectById 等通用方法对应的 MappedStatement
  3. 将生成好的 SQL 映射注册至 MyBatis 全局 Configuration,完全复用 MyBatis 原生执行流程,不改动底层源码

Q30:MP 分页插件如何配置?如何优化 Count SQL 陷阱?

⚠️ 重点:复杂 LEFT JOIN 查询中,自动生成的 COUNT(*) 性能极差!最佳实践:关闭自动 count,手动编写轻量级 count SQL。

// MP分页Count优化标准代码
Page<User> page = new Page<>(pageNum, pageSize);
// 关闭自动count,复杂联查必开
page.setSearchCount(false);

// 仅查询主表统计,性能提升数倍
Long total = userMapper.selectCount(wrapper);
page.setTotal(total);

List<User> list = userMapper.selectPage(page, wrapper);

Q31:MyBatis-Plus 的逻辑删除原理?

@TableLogic 标记字段,删除变为 UPDATE,查询自动过滤。底层通过 LogicSqlInjector 改写 SQL。

Q32:MyBatis-Plus 的乐观锁如何实现?

实体类添加 @Version 字段,更新时检查版本号是否匹配,匹配则更新并 +1。


八、生产环境避坑汇总表

坑点危害星级正确做法
SQL注入⭐⭐⭐⭐⭐能用 #{} 就别用 ${},动态表名需白名单校验
二级缓存分布式不一致⭐⭐⭐⭐⭐生产环境禁用 MyBatis 二级缓存,改用 Redis
MP分页COUNT陷阱⭐⭐⭐⭐⭐复杂查询手动设置 setSearchCount(false) + 手动count
批量插入性能差⭐⭐⭐⭐☆使用 <foreach>saveBatch,开启 rewriteBatchedStatements
Mapper重载⭐⭐⭐☆☆方法名保持唯一,避免映射冲突
逻辑删除未配置⭐⭐⭐⭐☆必须标注 @TableLogic,防止物理删除

九、课后面试真题练习

1. 分析题:某系统使用 MyBatis 二级缓存,关联表更新后其他查询读到旧数据,为什么?如何解决?

思路:二级缓存基于 Mapper namespace,关联表更新不会清空其他表的缓存。解决:关联表缓存在同一 namespace,或使用 cache-ref,或在分布式环境下直接禁用改用 Redis。

2. 代码题:使用 MyBatis-Plus 的 LambdaQueryWrapper 实现用户多条件分页查询(姓名模糊、年龄区间、状态精确),并处理复杂关联查询的 count 优化。

思路:参考 Q30 代码示例,使用 Lambda 表达式封装条件,关闭自动 count 并手动设置 total

3. 源码题:简述 MyBatis 插件(Interceptor)的拦截链构建过程。

思路Configuration 持有 InterceptorChain 存储全部插件;创建 Executor/StatementHandler 等四大对象时执行 pluginAll();循环调用每个拦截器 plugin 方法生成多层代理,形成责任链。PageHelper、MP 分页插件均基于此机制。


📊 你的学习进度

  • 当前:第90篇 / 共108篇 · 进阶篇:数据库与持久层框架(第83~90篇)
  • ✅ 已完成:基础篇44篇 + 第91~96篇(Redis/MQ)+ 第83~90篇
  • 📖 正在学:第90篇
  • ⏳ 待学习:第97~108篇(微服务/物联网/AI/设计模式/面试压轴)

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

👉 下一篇文章预告

《第91篇:Redis核心数据结构(2026版)》

内容简介:Redis 五种核心数据结构(String、Hash、List、Set、ZSet)底层实现与适用场景,HyperLogLog、Bitmap 高级结构,生产环境避坑与面试高频题。

🎁 福利提醒:评论区留言“MyBatis面试”可领取《MyBatis 面试 32 题速答卡》PDF。

📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值