MyBatis vs JPA:世界上没有坏技术。

“这个项目到底算什么?”

我现在公司的项目,可以说是一个“缝合栈”。MyBatisJPA 同时存在于同一个项目里。问题在于,最初写下这套代码的“造物主”,也就是最早那批成员,早就已经全部离职了。

留下来的我们,也就是现在的团队,非常困惑。到底是按照什么标准把这两种技术混着用的,连一份文档都没留下。于是情况只会越来越混乱。

最后,一个服务里做着相似功能,有的人还在钻 XML,有的人却在设计实体,整个团队变成了一种诡异的“技术无政府状态”。项目也越来越像一个难以维护的怪物,最终大家不得不开会。

“我们统一成一种技术栈吧。”

没有原则地混用技术,不是自由,只是混乱。

“JPA 不是太慢了,根本不能用吗?”

会议气氛很紧张。尤其是熟悉 MyBatis 的同事,强烈反对统一到 JPA。他们最核心的论点就是“速度”。

“你们不记得上次那个统计页面用 JPA 写完之后,光加载就花了 20 秒吗?如果 SQL 直接自己写,1 秒就出来了。去依赖一个我们无法完全控制的黑盒,风险太大了。”

确实,有些逻辑光是加载数据就要花几十秒。但我很确定,那不是技术本身的问题,而是“熟练度”的问题。我当场打开笔记本,把那段著名的“20 秒代码”调了出来。

那段代码惨不忍睹。它查询的是一个 List<Entity>,但每次循环访问关联对象时,都会单独再打一次数据库。这就是典型的N+1 问题

“这不是 JPA 慢,而是我们让 JPA 以一种低效的方式工作。你们看。”

我当场加上了 Fetch Join,把查询压缩成了一次。部署之后,原本 20 秒的加载时间直接降到了 1 秒。那一刻,同事们的眼神都变了。

在怪工具之前,先把说明书看完。

意外的发现:不是缝合怪,而是混合架构

既然对 JPA 的误解已经澄清了,那是不是接下来直接用 JPA 一统天下就行?真正拆开来看以后,我发现这也不是标准答案。

复杂的统计查询,或者几十万条数据的 Excel 下载,如果都用 JPA 来处理,对象映射成本太高,动态查询写起来也很别扭。相反,MyBatis 在这类任务上就显得非常直观而且高效。我开始疑惑:“别的公司到底怎么解决这个问题?” 带着这种郁闷,我整晚都在 Google 上搜索,翻各种技术博客。

让我意外的是,很多技术公司并没有执着于只用 JPA。一些团队会用 QueryDSL 来处理复杂查询性能问题,甚至也有很多团队和我们一样,把 MyBatis 一起用上。

那一刻我突然明白了:“啊,原来前任们并不是随便乱混用的。”

他们其实早就知道每种工具的优缺点,并且有意识地按职责拆分技术。真正的问题只是,他们走的时候没有把这些决策写成文档,导致留下来的我们根本不明白背后的意图,只顾着争论“为什么不统一”。

突破 JPA 的边界:QueryDSL 与 Projection

那么,能不能把 MyBatis 去掉,只靠 JPA 阵营里的技术来解决这个问题?这里登场的,就是 QueryDSLProjection

// 1. 僅定義所需資料的介面(不需要 DTO)
public interface DailyStat {
    String getDate();
    Long getTotalSales();
}

// 2. 透過 QueryDSL 或 JPA Repository 查詢
// 只從 DB SELECT 那兩個欄位,所以跟 MyBatis 一樣快
List<DailyStat> stats = repository.findDailySales();

了解这些技术之后,我发现自己已经没有太多理由再退回 MyBatis 的 XML 地狱了。因为在 JPA 生态内部,同样可以写出足够高性能的查询。

实战建议:别吵架,让它们共存

最终,我们团队没有选择“无条件统一”,而是选择了“有原则的共存”。(并且从长期来看,我们把迁移到 QueryDSL 作为目标。)

有意思的是,我们为了生存而选择的这套“写入(Command)用 JPA,读取(Query)用专用工具”的策略,从架构角度看,其实就是 CQRS(Command and Query Responsibility Segregation) 模式的一种非常基础的形态。

即使不做那种大张旗鼓的数据库拆分,只要在代码层面贯彻“命令与查询职责分离”的理念,项目就会整洁很多。

结语:技术无罪

我们经常会争论“JPA 才是最好的”或者“不是,MyBatis 才更适合实际开发”。但这次经历让我学到的是,世界上没有坏技术。有的只是,把某种技术用在了不合适的场景里。

JPA 像一根魔法杖,但咒语念错了就会爆炸。MyBatis 像一把结实的锤子,但它也会让你把所有问题都看成钉子。

如果你现在的团队也正在因为遗留代码,或者因为技术偏好不同而产生冲突,不妨先停下来想一想。也许这种混乱背后,藏着前辈开发者认真思考过的痕迹。把它找出来,再整理成明确的“规则”,这才是真正成熟开发团队该走的路。

發佈留言