一、MyBatis 拦截器
1、是什么
MyBatis 原生插件机制,底层基于 JDK 动态代理,代理 MyBatis 四大对象: Executor、StatementHandler、ParameterHandler、ResultSetHandler
2、什么时候触发、需要什么配置才会生效(重点新增)
- 默认不生效!必须手动配置注册拦截器才会走拦截逻辑
- MyBatis‑Plus 必须手动注入
MybatisPlusInterceptorBean,并且添加对应内部插件 - 只要该拦截器 Bean 存在,每一次执行 Mapper 增删改查都会触发
- 触发时机:SQL 已经生成完成,但还没发送给数据库执行,拦截器先加工处理
3、能干什么
拦截器不会从零组装完整 SQL 。 拿到已经生成好的原始 SQL,做解析、修改、追加条件;也可以修改入参、处理返回结果。
4、MybatisPlusInterceptor(Plus 核心复合拦截器)
必须手动配置 Bean 才生效,内部包含多个子插件:
- 分页插件:拿到原始 select 语句,解析 SQL,拼接 limit;额外生成 count 统计 SQL,封装 Page 分页对象
- 多租户:自动 where 后拼接 tenant_id = ?
- 逻辑删除:把 delete 语句改写为 update set deleted=1 where ...
- 乐观锁:自动拼接 version 版本条件
- 防全表更新删除:拦截不带 where 条件的 update/delete
拦截器代价: 需要运行时解析 SQL,有 CPU 开销;多个插件顺序错误会产生 bug;部分复杂 SQL 解析会出错。
5、MyBatis‑Flex 拦截器说明
框架自带 CRUD完全不依赖拦截器 ,无需配置、无 SQL 解析开销; 业务依旧可以自定义 MyBatis 拦截器做日志、监控、数据权限。
二、Wrapper 条件构造器
作用:动态组装 SQL 的 where 查询条件,避免手写字符串拼接,防止 SQL 注入
- QueryWrapper:直接写字段字符串,字段写错运行时才报错
- LambdaQueryWrapper:Lambda 方法引用,编译期校验字段,写错直接编译报错,项目优先使用
重点:Wrapper 只拼 where 条件,不能生成完整 SQL
三、执行流程对比
MyBatis‑Plus 执行流程
业务代码 → LambdaQueryWrapper 组装 where 条件 → BaseMapper 生成基础 SQL → MybatisPlusInterceptor 拦截器解析、改写 SQL → SQL 提交数据库执行
MyBatis‑Flex 执行流程
业务代码 → QueryChain/Wrapper 组装条件 → 框架内部直接拼接完整最终 SQL → 通过 @SelectProvider 交给 MyBatis 执行,没有拦截器二次解析改写步骤
四、MyBatis‑Flex 为什么理论更快
- 省去拦截器解析、改写现有 SQL的运行时开销
- APT 编译期生成表、字段常量,大幅减少运行时反射
- 依赖轻量化,仅依赖原生 MyBatis
重要提醒:绝大多数业务瓶颈在数据库,普通业务两者性能感知差距很小;高频简单单表查询Flex 优势更明显,不能过度夸大性能。
五、优缺点对比
MyBatis‑Plus
✅优点
- 国内生态成熟,网上资料、BUG 解决方案极多
- Wrapper 上手简单,代码生成器完善,团队学习成本低
❌缺点
- 分页、租户、逻辑删除全部靠拦截器实现,插件顺序容易踩坑
- 分页需要解析原始 SQL,部分复杂 SQL 解析存在 BUG
- 多表 join 能力弱,复杂关联基本要手写 XML
MyBatis‑Flex
✅优点
- CRUD 不走拦截器,性能更好,SQL 调试直观
- 原生支持多表查询:left join、union,大量场景不用写 XML
- APT 编译期校验字段,错误在编译阶段暴露,不报线上错
❌缺点
- 社区体量小,网上现成方案少,依赖官方文档 / 源码
- 老项目迁移成本高,团队有学习成本
六、面试选型话术
老项目、团队熟悉 MyBatis‑Plus,继续用 Plus,生态稳定; 新项目、多表查询多、追求性能和稳定性,优先 MyBatis‑Flex。
七、高频面试问答(完整版)
- 拦截器是组装完整 SQL 吗? 不是,拦截器是拿到已有 SQL,解析 + 修改 + 追加;Flex 才是直接拼完整 SQL。
- Flex 完全不能用拦截器吗? 框架 CRUD 不用;业务自定义拦截器(日志、监控、数据权限)依旧正常使用。
- LambdaWrapper 好处? 编译期校验字段,杜绝字符串写错导致的线上 BUG。
- Wrapper 作用? 专门动态构建 where 查询条件。
- Plus 分页为什么必须配置拦截器? Plus 分页功能完全依赖拦截器插件,不配置 Bean 分页直接失效,total 永远为 0。
- 拦截器什么时候会执行? 手动注册拦截器 Bean 后,所有 Mapper 增删改查都会经过拦截器链,不需要处理的 SQL 插件直接放行。