Java社招面试题:MyBatis为什么需要预编译?我用这次面试经历讲透了!

96 阅读5分钟



哈喽,大家好,我是小米,一个 31 岁、在 Java 世界里摸爬滚打十年的老程序员大哥哥。今天想和大家聊聊我最近面试中遇到的一道高频题——

“MyBatis 为什么需要预编译?”

说起来,这是一道我以为很基础,结果差点翻车的面试题……不卖关子了,我们进入正题。

故事的开始:一次“看似简单”的社招面试

最近因为老东家转型,我打算跳槽看看新的机会,于是投了几家公司,拿到了几个社招面试。某互联网公司,技术面二面,一个典型的老派面试官,戴眼镜、沉稳有礼,一看就是经验丰富的“代码艺术家”。

面试到中段,他突然问我一句:

“你用 MyBatis 开发过哪些项目?”

我想了想,说我最近三年一直用 Spring Boot + MyBatis 开发企业管理系统,熟悉 XML 映射、注解方式、分页插件、自定义拦截器啥的。

他说,“不错,那你能说说 MyBatis 为什么需要预编译吗?如果不预编译会有什么后果?”

我愣了一下。

这题,我知道是 SQL 的预编译,但突然这么问,还是让我有点懵。

我调整了下状态,说:“因为预编译可以防止 SQL 注入……还能提高性能……”

他说:“很好,那具体是怎么实现的?MyBatis 是怎么用预编译的?和 JDBC 的 PreparedStatement 是一个意思吗?”

这一刻,我感觉我的脑袋里有个“滴”地一声——滴水穿石也得有个方向吧!

于是我从头开始,给他讲了一个 “预编译和 MyBatis 的爱恨情仇” 的故事。

什么是预编译?PreparedStatement 是老朋友

我们得先搞清楚“预编译”到底是什么。

当我们用 JDBC 写原始 SQL 时,有两种选择:

vs.

第二种就是我们说的“预编译”。在这种方式下,SQL 语句会提前编译好,数据库把结构部分提前处理,只等你把参数一塞,它就能直接跑起来。

而且重点是,参数是“值”,不是“拼接”

于是,SQL 注入被防了,执行计划也能被缓存,性能提升也就自然来了。

那 MyBatis 怎么用预编译的?

MyBatis 不造轮子,它的底层其实就是封装了 JDBC 的 PreparedStatement。

当你写这样一个 Mapper 接口:

或者 XML 里这样写:

MyBatis 会把 #{name} 解析成一个“问号占位符 ? ”,并通过底层的 JDBC PreparedStatement 来进行参数设置:

所以你看到的 #{},其实就是一个语法糖,它最终会变成 ?,然后安全地填值进去。

这就是 MyBatis 中所谓的“预编译”。

如果不预编译会怎样?小米讲段“血泪史”

说到这里,我插了个小故事。

我当年刚入行那会儿,在一个外包项目里搞了个“拼接 SQL”的神器,用 Statement 拼接了一段“自由组合搜索语句”。

当用户输入用户名时,SQL 是这样:

结果有个哥们不怀好意,在输入框输入了:

于是,SQL 变成了:

完蛋!所有用户数据被查出来了!这就是最常见的 SQL 注入 攻击。

于是我意识到,拼接 SQL 是万恶之源。而 PreparedStatement + #{} 的方式,能安全、优雅地避免这个坑。

我和面试官说完这段后,他点头说,“不错,那你知道 MyBatis 的 ${} 和 #{} 有啥区别吗?”

我毫不犹豫:“${} 是字符串替换,真的会被拼接进 SQL,是不安全的;#{} 是值替换,会使用预编译,是安全的。”

性能提升是预编译的另一重意义

聊完安全性,咱们来谈谈性能。这其实是很多面试官爱追问的一点。

1. 预编译提升执行效率

数据库执行一条 SQL 的流程分三步:

  • 解析 SQL 语句
  • 生成执行计划
  • 执行

如果你每次执行的 SQL 结构一样,只是参数不同,那么用预编译(PreparedStatement)可以让数据库复用“执行计划”。

这样做的好处就是——

省下了反复编译 SQL 的时间,执行效率自然提升。

2. MyBatis 的执行器缓存机制

其实 MyBatis 还有个小心思。

在默认的 Executor 实现中(比如 ReuseExecutor、BatchExecutor),它会缓存一些 MappedStatement 和 SQL 的执行计划对象,避免每次都走创建流程。

换句话说,如果你写得规范,用得合理,MyBatis 本身就是一个“执行计划复用高手”。

总结复盘:为什么 MyBatis 需要预编译?

面试到了尾声,我做了个收尾总结,分享给你们:

  • 防止 SQL 注入: 使用 #{} 会被替换为 ? 占位符,底层使用 PreparedStatement,防止注入攻击;
  • 提高执行效率: 数据库可以复用执行计划,提升性能;
  • 降低系统资源消耗: 避免频繁解析 SQL,降低数据库压力;
  • MyBatis 本身设计理念: 遵循 JDBC 最佳实践,将 SQL 与参数分离,提高可维护性和可读性;

注意事项: 是“字符串替换”,容易被SQL注入,一定要慎用!比如拼接表名、字段名时可以用{} 是“字符串替换”,容易被 SQL 注入,一定要慎用!比如拼接表名、字段名时可以用 {},但参数永远别这么搞!

后记:这次面试我拿到了 Offer

这场面试过后,我收到了 offer,还被点名夸我“基础扎实”。

其实很多时候,面试问的不是多高级的算法,而是你对日常开发工具的理解是否 “知其然,知其所以然”

MyBatis 是我们日常开发中离不开的 ORM 工具,它的每一个设计,其实都不是“拍脑袋”决定的,背后有深厚的底层逻辑和工程经验。

结语:别让工具变成“黑箱”,你得懂它在干嘛!

写代码就像开车,工具是方向盘、发动机、刹车。如果你只知道踩油门,万一前面是个坑怎么办?

了解工具底层逻辑,是从“写代码”走向“写好代码”的必经之路。

END

今天的分享到这里,希望你在下一次面试遇到类似问题时,也能像我一样,胸有成竹地讲出背后的故事!

如果你喜欢这样的面试题解析风格,别忘了点个“”或者“在看”,你们的支持,是我继续写作的动力!

我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!