Richard's Blog

Mybatis还是JPA

字数统计: 1.7k阅读时长: 6 min
2024/01/04 Share

记得在刚还没毕业准备找工作的时候,为了能更有竞争力,在网上找了一套教程跟着做,当时忘记是哪里找的了,是一套 spring + struts2 + hibernate 的技术栈,我照着教程写了一篇,当时没什么感觉,觉得 HQL 也挺方便的,而且大多数时候不需要写 HQL,Hibernate 的注解会自动映射 Entity,只是在编码时需要注意 Entity 的状态,是在线还是离线状态,记得当时为了省事,不管在线还是离线最后都 save 一下。

虽然当时已经看到很多文章都会说阿里用 Mybatis,Mybatis 就是好之类的,但是不知道是不是因为我学的教程的原因,找到的第一份工作也是使用 Hibernate 的,但是是一套很老的框架,MVC 使用的是 struts1.x。当时那套框架被技术主管做了深度定制,虽然是 hibernate,但是只需要写一条包含了各种符号的 Hibernate 就可以适配大多数情况,Service 层也其实就是调一下框架的方法就可以直接查询。

再后来跳槽就没有再遇到过使用 Hibernate/JPA 的公司了,之后的编码就在无尽的 mapper.xml、mapper.java 之间切换,遇到过很多问题。比如直接用 generator 生成 mapper 的 xml 和类,然后手动修改了一些生成的出来的 SQL,又被其他同事重新生成给覆盖掉,导致程序出错。比如为了不写基础 mapper.xml,引入了 Mybatis-Plus,然后觉得 Mybatis-Plus 的 join 功能不是很方便,又引入了 Mybatis-Plus-Join,看着这些依赖所解决的问题,不经陷入了思考。

在使用 Mybatis 家族一段时间后,有几个问题一时困扰着我,自动生成真的好吗,Mybatis的最佳实践到底是什么,阿里用Mybatis难道Mybatis就一定是对的选择吗,为什么不使用JPA?

自动生成真的好吗

我认为是不好的,我对生成出来的代码是否真的能满足需求一直有一种不信任感,虽然问过很多这样编码的同学,他们说反正生成出来不满足改一下就好了,总比自己写来的方便。但是我总是怕万一改漏了呢,万一生成的默认代码存在无法马上察觉的问题,上生产后导致数据错乱怎么办。生成的代码总感觉不是刚刚好能满足我的需求的代码,总会在某些情况下出现一些没有用上但是没人删除的代码。这部分代码在修改的时候也极为麻烦,不确定是否真的没有使用到,导致修改的时候畏首畏尾,无奈还是重新写一个算了。感觉很多”屎山”就是这么来的

阿里用 Mybatis 难道 Mybatis 就一定是对的选择吗

虽然没在阿里就职过,不清楚阿里内部对 Mybatis 的使用是什么情况。但是在反复看了很多次 Mybatis 的官网和各种关于 Mybatis 的资料后,突然有一种感觉,绝大多数项目其实根本不需要 Mybatis,他们都用错了。在我看来更多的情况特别是引入了 Mybatis-Plus 这个组件的项目更应该使用 JPA。

我认为 Mybatis 作为一个动态SQL的工具,不应该只是单纯的对照着表结构做查询,单纯的

1
select * from table;

然后返回一个 table 的表对象这种需求,直接使用 JPA 更好,还能省去编写/生成 mapper.xml 的问题。

所以 Mybatis 的最佳实践到底是什么

在我尝试了几个项目后,我觉得 Mybatis 的最佳实践是让所有包括 Controller/Service 层的代码更贴近业务,面向业务编程。
我身边的绝大部分 Java Web 开发都有一个惯性,先把业务代码转换为对哪几张表查询,用表字段去拼凑所需要的数据,查询的语句也是简单语句,中的定义也只有等少数标签。

我认为这不是使用 Mybatis 的正确方法,正确方法应该是的定义就已经尽量接近业务所需要的数据结构,然后使用比如等标签让 Mybatis 帮助我们组装,对应的

我印象最深的是有一个需求是需要返回一个复合对象,主要对象所在的表对其他表有 OneToMany 也有 ManyToOne 的关系,还需要多层关联数据,刚好查询的 SQL 都包含了这些信息,于是我写了只在 Mapper.xml 里写了一个这样的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<resultMap>
<id/>
<result/>
<collection>
<id/>
<result/>
<association>
<id/>
<result/>
</association>
</collection>
<collection>
<id/>
<result/>
</collection>
</resultMap>
<select>
...
</select>

就已经完成了业务需要的返回数据。我认为这才是 Mybatis 的正确使用方式。

在 SQL 编写上,在我周围鲜少有人使用等标签,我觉得这简直浪费了 Mybatis 的动态SQL的特点,无尽的浪费了动态SQL的神奇。虽然这样会使得 SQL 语句变得破碎,阅读和排查问题更加繁琐,但是在实践后发现,其实用到的地方并不多,所以不太会出现大量碎片 SQL 的情况,但是对于能把相同的 SQL 抽出来以不同的入参像调用方法一样使它生成略有区别的 SQL 还是很舒服的。

Mybatis 与 JPA

如果在选择技术栈的时候还没有领悟面向业务编程的概念,我个人还是建议使用 JPA,虽然有的人可能看了一些文章会说 JPA 写复杂 SQL 麻烦,没有 Mybatis 好,但是像上面说的项目,Mybatis 最后演变成Mybatis + Mybatis-Plus + Mybatis-Plus-Join就真的比 JPA 写复杂 SQL 好吗。

不管怎么说 JPA 还是 Java 官方定义的一套规范,虽然现在主流实现还是只有 Hibernate,但是如果做不到面向业务编程的话,JPA 还是更方便,只是中文资料确实是比 Mybatis 少就是了。做程序员不会英语的话还是趁早转行。

有能力面向业务编程后,使用 Mybatis 时就会发现,根本不需要什么生成代码,你的 Service 是根据业务来的,没有哪两个业务是相同的逻辑,也极少出现单表查询,这时的 Mybatis 会让你只需要关注业务,数据交给 Mybatis 帮你组装。

CATALOG
  1. 1. 自动生成真的好吗
  2. 2. 阿里用 Mybatis 难道 Mybatis 就一定是对的选择吗
  3. 3. 所以 Mybatis 的最佳实践到底是什么
  4. 4. Mybatis 与 JPA