欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

持久层框架JPA与Mybatis该如何选型

程序员文章站 2023-10-28 22:46:40
一、现状描述 目前java 持久层ORM框架应用最广泛的就是JPA和Mybatis。JPA只是一个ORM框架的规范, 对该规范的实现比较完整就是Spring Data JPA(底层基于Hibernate实现),是基于Spring的数据持久层框架,也就是说它只能用在Spring环境内。Mybatis也 ......

一、现状描述

目前java 持久层orm框架应用最广泛的就是jpa和mybatis。jpa只是一个orm框架的规范, 对该规范的实现比较完整就是spring data jpa(底层基于hibernate实现),是基于spring的数据持久层框架,也就是说它只能用在spring环境内。mybatis也是一个优秀的数据持久层框架,能比较好的支持orm实体关系映射、动态sql等。

笔者在学习这两个框架的过程中,看过不少的帖子,每当有帖子比较这两个框架的优缺点,就引来一场论战。从笔者的角度,为什么国内的开发人员或者开发团队较少使用jpa?为了避免有人抨击我,我特意去做了一下国内某度指数搜索,这个数据骗不了人。

持久层框架JPA与Mybatis该如何选型

图中蓝色线条为mybatis搜索量,绿色为jpa搜索量。如果你换一个国外的搜索指数,你会得到一个完全不同的结果。那么这是为什么呢?我们还要从jpa的特点说起:

  • jpa对于单表的或者简单的sql查询非常友好,甚至可以说非常智能。他为你准备好了大量的拿来即用的持久层操作方法。甚至只要写findbyname这样一个接口方法,他就能智能的帮你执行根据名称查找实体类对应的表数据,完全不用写sql。
  • 但是,jpa对于多表关联查询以及动态sql、自定义sql等非常不友好。对于jpa来说,一种实现实现方式是querydsl,实现的代码是下面这样的。我想问:你希望用这样的代码代替sql么?
jpaqueryfactory queryfactory = new jpaqueryfactory(em);
jpaquery<tuple> jpaquery = queryfactory.select(qtcity.tcity,qthotel.thotel)
                                .from(qtcity.tcity)
                                .leftjoin(qthotel.thotel)
                                .on(qthotel.thotel.city.longvalue().eq(qtcity.tcity.id.longvalue()));
//添加查询条件
jpaquery.where(predicate);
//拿到结果
return jpaquery.fetch();

另一种方法是使用nativequery,我仍然想问:你希望在java代码里面用拼字符串的方式写sql么?

@entity
@namednativequeries(value={
        @namednativequery(
                name = "studentinfobyid",
                query = " select * from student_info " 
                      + " where stu_id = ? ",
                resultclass = student.class
                )
})
@table(name="student_info")

以上的这部分实现还没有考虑到动态sql的问题,如果考虑到动态sql,写法会更复杂。所谓的动态sql就是:根据传入参数条件的不同,构造不同的sql,很多的比较这两个框架的文章都忽略了动态sql的问题,这方面mybatis支持的更好。mybatis写的动态sql说到底还是sql,而不是java代码或者java代码拼字符串。程序员特别排斥几件事:

  • 将复杂关联关系的sql写在java代码里面,拼串书写不方便
  • sql是最能表达实体关系查询的语言,程序员不希望使用异化sql语言。
  • 程序员不希望学习不通用的东西,显然sql大家都会
  • jpa虽然将大部分操作封装起来了,也挺好用的,但是sql调优怎么做?

可以使用spring-data-jpa-extra解决jpa的拼串书写和sql异化的问题。但是根据笔者的使用情况,spring-data-jpa-extra是一个个人开发者项目,用于生产还很不成熟,对于多数据源处理、复杂类型处理等还有很多的问题。

二、劣币驱逐良币?

持久层框架JPA与Mybatis该如何选型

然而,另外有一派观点,你看人家国外的程序员怎么都用jpa?你不去学习新东西,还不让别人用?jpa使用很方便啊,唯一缺点就是复杂关联sql支持差一点,但是只要你学一下也还可以支持啊,你们这是劣币驱逐良币。如果经过很好的实体关系模型的设计,jpa显然是最优解,程序员写的sql还真不如jpa根据实体关系生成的sql。笔者要说,这种观点也是有道理的。但是,笔者要说并不是国内程序员不愿意学习,而是另有原因。

  • 首先,笔者长年从事远程工作,与国外程序员接触较多。他们习惯使用jpa的一个原因,真的是因为他们国家的应用规模太小了,比起国内的一个应用动则上百万的用户相比,他们在数据库设计与调优的需求上显然更从容。
  • 国外的应用设计往往更简洁,而国内的应用需求往往功能性更强。如果不信,你可以去看看工作流,什么会签、流程回退什么的都是我们发明的,他们没有。你让他们用jpa写一个我们的工作流应用试一试,累吐血他们也做不到。
  • 异化sql或者代码里面写sql,一定程度上增加了学习成本和使用成本。所以用的人少,用的人少你就得迁就团队中的大部分人。

说完以上几点,mybatis为什么在国内会有如此多的使用者及使用厂商就不难理解了。mybatis还可以使用如:mybatis-plus或者代码自动生成来弥补易用性上的不足。jpa的身材、家室、性格样样都是满分,就是脸长得磕碜点难以处理社交关系。mybatis虽说在各方面都不优秀,身材还可以、样貌也还说得过去、性格也还好。关键是你说什么都听你的,还有愿意帮他化妆的朋友。要你说你选哪一个?

那么,有的人会说,你这是抬杠?国外就没有受众数量多、功能性强的互联网应用了么?恐怕比国内还多吧,这个也是事实。但是从比例上讲还是国内更多,比例决定开发人员选择技术的方向。这也导致了一个惯性思维,他们平时就用jpa学习训练,所以写大型服务应用的时候也用jpa。那么,他们写jpa会写复杂sql么?答案是很少会用到,甚至有的国外公司就明令禁止写关联查询sql。那怎么办?不用关联sql怎么开发业务需求?不会啊。

三、服务拆分或微服务

持久层框架JPA与Mybatis该如何选型

国内现在也有越来越多的公司,进行微服务的落地,然而真正落地比较好的企业少之又少。这和多表关联查询有什么关系?我们先来实现这样一个需求:查询属于a角色相关的所有的业务b数据。

  • 如果我们开发的是传统的单体应用,我们可能是把角色表a和业务表b进行关联查询,然后得到查询结果
  • 如果我们做的是微服务,我们可能是拆分为权限服务a、业务服务b。先去访问a服务接口获取角色标志信息,然后再根据角色标志信息去业务服务b接口获取业务数据。

那么有的人会说,访问两个接口一定比访问一个接口更慢吧!这个真的不是,如果我们做微服务,一定是我们的应用规模及数据量到达了一定程度。也一定会考虑分表分库、负载均衡、服务拆分细化等问题,当分布式的开发方式被应用越多,多表关联查询使用的机会也就越少。拆分后的服务由于功能单一、负载分流等原因,访问速度往往比大数据量数据集中存储、多服务集中部署的应用会快很多。

问题回来了,不用关联sql怎么开发程序?总的来说就是通过合理的服务拆分、应用的界面数据的组织关系的合理的设计,团队拥有比较好的微服务落地经验,是可以实现不使用关联查询sql开发应用的。大家也知道,nosql越来越流行,绝大部分的nosql数据库都没有所谓的关联关系。

四、框架对比选型

对比项 spring data jpa mybatis
单表操作方式 只需继承,代码量极少,非常方便。而且支持方法名用关键字生成sql 可以使用代码生成工具或mybatis-plus等工具,也很方便,但相对jpa要弱一些。
多表关联查询 不太友好,动态sql使用不够方便,而且sql和代码耦合到一起 友好,可以有非常直观的动态sql
自定义sql sql写在注解里面,写动态sql有些费劲       sql可以写在xml里面,是书写动态sql语法利器。也支持注解sql。     
学习成本 略高       较低 ,基本会写sql就会用      

总结一下笔者的观点:

  • 如果你是自己开发“小而美”的应用,建议你使用jpa
  • 如果你是开发大而全的企业级应用,当然要遵从团队的技术选型。这个技术选型在国内通常是mybatis。
  • 如果你们公司的管理非常规范,微服务落地经验也非常成熟,可以考虑在团队项目中使用jpa。少用或不用关联查询。

    期待您的关注

  • 博主最近新写了一本书:《手摸手教您学习springboot系列-16章97节》
  • 本文转载注明出处(必须带连接,不能只转文字):。