Java ORM 哪家强?10个ORM框架测试对比与选型建议

前言:

Java 领域的ORM(Object-Relational Mapping)框架有很多,各家的性能和使用体验如何?本文将对比体验以下的Java ORM框架,包括Spring JDBC、Spring Data JPA + Hibernate、QueryDSL、jOOQ、GraphQL、MyBatis、MyBatis-dynamic-sql、MyBatis-plus、Fluent-mybatis、MyBatis-flex,以帮助开发者选型。

一、性能测试对比

测试背景:

我们以diboot的操作日志表为基准,字段十几个,测试表中数据量约2万条。分别测试对比以下ORM框架:Spring JdbcTemplate、Spring JdbcClient、Spring data JPA、Mybatis、Mybatis-plus、Mybatis-flex。*(其他框架会在使用体验章节介绍) *

测试以下步骤:

  • 循环执行 1000 次读LIKE 查询,重复多次
  • 循环执行 1000 次写插入,重复多次测试

测试结果:

(注:因Mybatis-plus 和 Mybatis-flex 存在冲突无法共存,所以我们拆分为2个测试用例分别测试)

总结:

  • Spring JdbcTemplate 是最接近原生JDBC的性能,以此为基准,Spring 最新的JdbcClient是在JdbcTemplate的基础上在对象映射上做了轻量封装,二者的读写性能都非常优秀。
  • Mybatis 的读写性能仅次于Spring JdbcClient,非常优秀。
  • Mybatis-plus 的读性能较好,在Mybatis的基础上损耗较小,优于Mybatis-flex(二者都是通过Lambda构建查询)。写性能上二者相差不大。
  • JPA的读写性能不如Mybatis-plus(与Mybatis-flex混合测试还会导致无法写入)。

二、使用体验对比

Spring JdbcTemplate、JdbcClient

优点: 接近原生JDBC的性能 缺点: 仅提供了基础的对象映射转换处理,需要在Java中写大量的SQL语句,表多的话很难维护 示例:

java 复制代码
// 查询用法示例
List<IamOperationLog> dataList = jdbcClient
                .sql("select * from iam_operation_log where business_obj LIKE ?")
                .param("%"+keyword+"%")
                .query(IamOperationLog.class)
                .list();

Spring Data JPA + Hibernate

优点: 有Spring体系的支持,关注对象模型不太关注SQL的简单场景用起来比较容易 缺点: 过度抽象,隐藏了SQL实现,背后的Hibernate驾驭起来也比较困难,复杂SQL条件构建与扩展都不方便 示例:

java 复制代码
// 查询用法示例
IamOperationLog iamOperationLog = new IamOperationLog().setBusinessObj(keyword);
List<IamOperationLog> dataList = jpaRepository.findAll(Example.of(iamOperationLog));

QueryDSL

优点: 支持APT自动生成构建SQL所需的DSL类;可以作为JPA方案的补充,扩展完善其查询条件构建等能力 缺点: 国内比较小众,复杂SQL实现繁琐 示例:

java 复制代码
// 查询用法示例
List<IamOperationLog> dataList = queryFactory.selectFrom(iamOperationLog)
    .where(iamOperationLog.businessObj.like('%'+keyword+'%'))
    .fetch();

jOOQ

优点: SQL构建方式相对优雅,写法接近原生SQL 缺点: 数据库支持少(开源版仅支持MySQL、PostgreSQL、SQLite等),国内比较小众 示例:

java 复制代码
// 查询用法示例
// 不使用APT生成DSL辅助类,写起来还是挺繁琐的
Query query = create.select(field("BOOK.TITLE"),field("AUTHOR.FIRST_NAME"),field("AUTHOR.LAST_NAME"))
.from(table("BOOK")).join(table("AUTHOR")).on(field("BOOK.AUTHOR_ID").eq(field("AUTHOR.ID")))
.where(field("BOOK.PUBLISHED_IN").eq(2008));
// 使用APT生成DSL辅助类,写起来相对顺畅
Query query = create.select(BOOK.TITLE, AUTHOR.FIRST_NAME, AUTHOR.LAST_NAME)
    .from(BOOK).join(AUTHOR)
    .on(BOOK.AUTHOR_ID.eq(AUTHOR.ID))
    .where(BOOK.PUBLISHED_IN.eq(2008)); 

List<Object> bindValues = query.getBindValues();

GraphQL

优点: 设计思路新颖 缺点: 只热过一阵子,把查询构建(业务逻辑)交给前端注定过于挑战开发者习惯,尤其是前后端分离场景下

javascript 复制代码
// GraphQL 查询,注意是:前端构建查询请求
author(id: "7") {
  id
  name
  avatarUrl
  articles(limit: 2) {
    name
    urlSlug
  }
}

MyBatis

优点: 性能优秀,使用简单,复杂SQL可以写在XML中方便统一维护,复杂项目更可控 缺点: 手写SQL过多,缺失通用Mapper、联表SQL手写复杂

xml 复制代码
<!-- 查询用法示例 -->
<select id="getMatchedLog" resultType="com.diboot.ormpk.entity.IamOperationLog">
    select *
    from iam_operation_log
    where business_obj LIKE #{keyword,jdbcType=VARCHAR}
</select>

MyBatis-dynamic-sql

优点: Mybatis官方出品的支持多表查询的动态SQL构建解决方案 缺点: 缺少APT自动生成方案,手写代码过多,使用起来缺失一点优雅

xml 复制代码
// 查询用法示例
SelectStatementProvider selectStatement = select(id, animalName, bodyWeight, brainWeight)
            .from(animalData)
            .where(id, isIn(1, 5, 7))
            .and(bodyWeight, isBetween(1.0).and(3.0))
            .orderBy(id.descending(), bodyWeight)
            .build().render(RenderingStrategies.MYBATIS3);
List<AnimalData> animals = mapper.selectMany(selectStatement);

MyBatis-plus

优点: Mybatis的扩展框架,性能较好,支持通用Mapper等,单表CRUD、查询条件构建写起来比较优雅 缺点: 缺少联表查询方案(可使用 Diboot core 内核实现)

java 复制代码
// 查询用法示例
LambdaQueryWrapper<IamOperationLog> queryWrapper = new LambdaQueryWrapper<IamOperationLog>()
        .like(IamOperationLog::getBusinessObj, keyword);
List<IamOperationLog> logList = iamOperationLogMPMapper.selectList(queryWrapper);

Fluent-mybatis

优点: 借鉴了jOOQ的实现思路 缺点: 已停更

java 复制代码
// 查询用法示例
StudentQuery query = new StudentQuery().where.userName().eq("u2").end();
List<StudentEntity> users = mapper.listEntity(query);

MyBatis-flex

优点: Mybatis的扩展框架,支持通用Mapper,支持APT生成DSL辅助类,支持多表,动态SQL构建也相对优雅。像是借鉴了众多ORM的优势实现的一个既要又要的解决方案。 缺点: 查询性能还有优化空间(v1.8.x版本),稳定性还有待验证

java 复制代码
// 查询用法示例
// 1. 不使用APT生成DSL辅助类,Lambda写起来类似Mybatis-plus
QueryWrapper queryWrapper = QueryWrapper.create().like(IamOperationLog::getBusinessObj, keyword);
List<IamOperationLog> logList = iamOperationLogMFMapper.selectListByQuery(queryWrapper);

// 2. 使用APT生成DSL辅助类,写起来类似jOOQ
queryWrapper = QueryWrapper.create().from(IAM_OPERATION_LOG).and(IAM_OPERATION_LOG.BUSINESS_OBJ.like(keyword));
logList = iamOperationLogMFMapper.selectListByQuery(queryWrapper);

三、总结与选型建议

Java ORM虽然很多,综合下来目前主流的还是JPA(Hibernate)和Mybatis两大阵营。

  • Mybatis拥有良好的性能和应对复杂场景的能力,国内使用更广泛是有理由的,个人建议首选站队Mybatis,除非你的项目非常简单。
  • 针对Mybatis的不足,如果你追求稳健,可以使用 MyBatis-plus + Diboot 。如果你的开发场景能够接受尝鲜,可以使用 Mybatis-flex(Diboot 后期也可能会适配)。
相关推荐
沛沛老爹10 天前
Python Django全功能框架开发秘籍
python·django·orm·web开发·模板引擎·项目部署·表单处理
掉头发的王富贵15 天前
【JOOQ】同事凭什么说它是世界上最好用的ORM框架
后端·mybatis·orm
o0向阳而生0o20 天前
68、.NET Entity Framework(EF)
.net·orm·ef
xiangji23 天前
.net 实现 CQRS 的的一个设想
orm·sqlbuilder
却尘1 个月前
当全世界都在用 Rust 重写一切时,Prisma 却选择了反方向
前端·数据库·orm
喵个咪1 个月前
开箱即用的GO后台管理系统 Kratos Admin - 代码生成工具集
微服务·orm·protobuf
xiangji1 个月前
ShadowSql.net之正确使用方式
orm·dapper·可扩展·sqlbuilder·面向接口
MyikJ1 个月前
Java求职面试:从Spring到微服务的技术挑战
java·数据库·spring boot·spring cloud·微服务·orm·面试技巧
Jaising6661 个月前
Mybatis Plus 多租户实现思路分析
spring boot·mybatis·orm
xiangji1 个月前
ShadowSql之表达式树
orm·sqlbuilder