记得在刚还没毕业准备找工作的时候,为了能更有竞争力,在网上找了一套教程跟着做,当时忘记是哪里找的了,是一套 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 的正确方法,正确方法应该是
我印象最深的是有一个需求是需要返回一个复合对象,主要对象所在的表对其他表有 OneToMany 也有 ManyToOne 的关系,还需要多层关联数据,刚好查询的 SQL 都包含了这些信息,于是我写了只在 Mapper.xml 里写了一个这样的定义
1 | <resultMap> |
就已经完成了业务需要的返回数据。我认为这才是 Mybatis 的正确使用方式。
在 SQL 编写上,在我周围鲜少有人使用动态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 帮你组装。