几个数据持久化框架 MyBatis、Hibernate、JPA、JOOQ和 JDBC Template 的比较

来源:segmentfault.com/a/1190000018472572
由于项目须要选择数据持久化框架,看了一下主要几个流行的和不流行的框架,对于复杂业务系统,最终的结论是,JOOQ是整体上最好的,惋惜不是彻底免费,最终选择JDBC Template。
Hibernate和Mybatis是使用最多的两个主流框架,而JOOQ、Ebean等小众框架则知道的人很少,但也有不少独特的优势;
而JPA则是一组Java持久层Api的规范,Spring Data JPA是JPA Repository的实现,原本和Hibernate、Mybatis、JOOQ之类的框架不在同一个层次上,但引入Spring Data JPA之类框架以后,咱们会直接使用JPA的API查询更新数据库,就像咱们使用Mybatis同样,因此这里也把JPA和其余框架放在一块儿进行比较。
一样,JDBC和其余框架也在同一层次,位于全部持久框架的底层,但咱们有时候也会直接在项目中使用JDBC,而Spring JDBC Template部分消除了使用JDBC的繁琐细节,下降了使用成本,使得咱们更加愿意在项目中直接使用JDBC。
01 
SQL封装和性能
在使用Hibernate的时候,咱们查询的是POJO实体类,而再也不是数据库的表,例如hql语句 select count(*) from User,里面的User是一个Java类,而不是数据库表User。
这符合ORM最初的理想,ORM认为Java程序员使用OO的思惟方式,和关系数据库的思惟方式差距巨大,为了填补对象和关系思惟方式的鸿沟,必须作一个对象到关系的映射。
在Java的对象世界中,程序员可使用纯的对象的思惟方式,查询POJO对象,查询条件是对象属性,再也不须要有任何表、字段等关系的概念,这样java程序员就更容易作持久层的操做。
JPA能够视为Hibernate的儿子,也继承了这个思路,把SQL完全封装起来,让Java程序员看不到关系的概念,用纯的面向对象思想,从新创造一个新的查询语言代替sql,好比hql,还有JPQL等。支持JPA的框架,例如Ebean都属于这种类型的框架。
但封装SQL,使用另外一种纯的面向对象查询语言代替sql,真的可以让程序员更容易实现持久层操做吗?MyBatis的流行证实了事实并不是如此,至少在大多数状况下,使用hql并不比使用sql简单。
首先,从不少角度上看,hql/JPQL等语言更加复杂和难以理解;其次就是性能上明显下降,速度更慢,内存占用巨大,并且还很差优化。最为恼火的是,当关系的概念被替换为对象的概念以后,查询语言的灵活性变得不好,表达能力也比sql弱不少。写查询语句的时候受到各类各样的限制,一个典型的例子就是多表关联查询。
无论是hibernate仍是jpa,表之间的链接查询,被映射为实体类之间的关联关系,这样,若是两个实体类之间没有(实现)关联关系,你就不能把两个实体(或者表)join起来查询。
这是很恼火的事情,由于咱们不少时候并不须要显式定义两个实体类之间的关联关系就能够实现业务逻辑,若是使用hql,只是为了join咱们就必须在两个实体类之间添加代码,并且还不能逆向工程,若是表里面没有定义外键约束的话,逆向工程会把咱们添加的关联代码抹掉。
MyBatis则是另一种类型的持久化框架,它没有封装SQL也没有建立一种新的面相对象的查询语言,而是直接使用SQL做为查询语言,只是把结果填入POJO对象而已。
使用sql并不比hql和JPQL困难,查询速度快,能够灵活使用任意复杂的查询只要数据库支持。从SQL封装角度上看,MyBatis比Hibernate和JPA成功,SQL本不应被封装和隐藏,让Java程序员使用SQL既不麻烦也更容易学习和上手,这应该是MyBatis流行起来的重要缘由。
轻量级持久层框架JOOQ也和MyBatis同样,直接使用SQL做为查询语言,比起MyBatis,JOOQ虽然知名度要低得多,但JOOQ不但和MyBatis同样能够利用SQL的灵活性和高效率,经过逆向工程,JOOQ还能够用Java代码来编写SQL语句,利用IDE的代码自动补全功能,自动提示表名和字段名,减小程序员记忆负担,还能够在元数据发生变化时发生编译错误,提示程序员修改相应的SQL语句。
Ebean做为一种基于JPA的框架,它也使用JPQL语言进行查询,多数状况下会让人很恼火。但听说Ebean不排斥SQL,能够直接用SQL查询,也能够用相似JOOQ的DSL方式在代码中构造SQL语句(仍是JPQL语句?),但没用过Ebean,因此具体细节不清楚。
JDBC Template就不用说了,它根本没作ORM,固然是纯SQL查询。利用Spring框架,能够把JDBC Template和JPA结合起来使用,在JPA很差查询的地方,或者效率低很差优化的地方使用JDBC,缓解了Hibernate/JPA封装SQL形成的麻烦,但我仍没看到任何封装SQL的必要性,除了给程序员带来一大堆麻烦和学习负担以外,没有太明显的好处。
02 
DSL和变化适应性
为了实现复杂的业务逻辑,不管是用SQL仍是hql或者JPQL,咱们都不得不写不少简单的或者复杂的查询语句,ORM没法减小这部分工做,最可能是用另外一种面向对象风格的语言去表达查询需求,如前所述,用面向对象风格的语言不见得比SQL更容易。
一般业务系统中会有不少表,每一个表都有不少字段,即使是编写最简单的查询语句也不是一件容易的事情,须要记住数据库中有哪些表,有哪些字段,记住有哪些函数等。写查询语句不少时候成为一件头疼的事情。
QueryDSL、JOOQ、Ebean甚至MyBatis和JPA都设计一些特性,帮助开发人员编写查询语句,有人称之为“DSL风格数据库编程”。最先实现这类功能的多是QueryDSL,把数据库的表结构逆向工程为java的类,而后可让 Java 程序员可以用java的语法构造出一个复杂的查询语句,利用IDE的代码自动补全功能,能够自动提示表名、字段名、查询语句的关键字等,很成功的简化了查询语句的编写,免除了程序员记忆各类名字、函数和关键字的负担。
QueryDSL有不少版本,但用得多的是QueryDSL JPA,能够帮助开发人员编写JPQL语句,如前所述,JPQL语句有不少局限不如SQL灵活高效。后来的JOOQ和Ebean,基本上继承了QueryDSL的思路,Ebean基本上仍是JPA风格的ORM框架,虽然也支持SQL,但不清楚其DSL特性是否支持SQL语句编写,在官网上看到的例子都是用于构造JPQL语句。
这里面最成功的应该是JOOQ,和QueryDSL不一样,JOOQ的DSL编程是帮助开发人员编写SQL语句,抛弃累赘的ORM概念,JOOQ这个功能很是轻小,很是容易学习和使用,同时性能也很是好,不像QueryDSL和Ebean,须要了解复杂的JPA概念和各类奇异的限制,JOOQ编写的就是普通的SQL语句,只是把查询结果填充到实体类中(严格说JOOQ没有实体类,只是自动生成的Record对象),JOOQ甚至不必定要把结果转换为实体类,可让开发人员按照字段取得结果的值,相对于JDBC,JOOQ会把结果值转换为合适的Java类型,用起来比JDBC更简单。
传统主流的框架对DSL风格支持得不多,Hibernate里面基本上没有看到有这方面的特性。MyBatis提供了"SQL语句构建器"来帮助开发人员构造SQL语句,但和QueryDSL/JOOQ/Ebean差不少,不能提示表名和字段名,语法也显得累赘不像SQL。
JPA给人的印象是复杂难懂,它的MetaModel Api继承了特色,MetaModel API+Criteria API,再配合Hibernate JPA 2 Metamodel Generator,让人有点QueryDSL JPA的感受,只是绕了一个大大的弯,叠加了好几层技术,最后勉强实现了QueryDSL JPA的简单易懂的功能。
不少人不推荐JPA+QueryDSL的用法,而是推荐JPA MetaModel API+Criteria API+Hibernate JPA 2 Metamodel Generator的用法,让人很难理解,也许是由于这个方案是纯的标准的JPA方案。
数据库DSL编程的另外一个主要卖点是变化适应性强,数据库表结构在开发过程当中一般会频繁发生变化,传统的非DSL编程,字段名只是一个字符串,若是字段名或者类型改变以后,查询语句没有相应修改,编译不会出错,也容易被开发人员忽略,是bug的一个主要来源。
DSL编程里面,字段被逆向工程为一个java类的属性,数据库结构改变以后,做为java代码一部分的查询语句会发生编译错误,提示开发人员进行修改,能够减小大量bug,减轻测试的负担,提升软件的可靠性和质量。
03 
跨数据库移植
Hibernate和JPA使用hql和JPQL这类数据库无关的中间语言描述查询,能够在不一样数据库中无缝移植,移植到一个SQL有巨大差异的数据库一般不须要修改代码或者只须要修改不多的代码。Ebean若是不使用原生SQL,而是使用JPA的方式开发,也能在不一样数据库中平滑的移植。
MyBatis和JOOQ直接使用SQL,跨数据库移植时都不免要修改SQL语句。这方面MyBatis比较差,只有一个动态SQL提供的特性,对于不一样的数据库编写不一样的sql语句。
JOOQ虽然没法像Hibernate和JPA那样无缝移植,但比MyBatis好不少。JOOQ的DSL很大一部分是通用的,例如分页查询中,Mysql的limit/offset关键字是很方便的描述方式,但Oracle和SQLServer的SQL不支持,若是咱们用JOOQ的DSL的limit和offset方法构造SQL语句,不修改移植到不支持limit/offset的Oracle和SQLServer上,咱们会发现这些语句还能正常使用,由于JOOQ会把limit/offset转换成等价的目标数据库的SQL语句。
JOOQ根据目标数据库转换SQL语句的特性,使得在不一样数据库之间移植的时候,只须要修改不多的代码,明显优于MyBatis。
JDBC Template应该最差,只能尽可能使用标准sql语句来减小移植工做量。
04 
安全性
通常来讲,拼接查询语句都会有安全隐患,容易被sql注入攻击。不管是jdbc,仍是hql/JPQL,只要使用拼接的查询语句都是不安全的。对于JDBC来讲,使用参数化的sql语句代替拼接,能够解决问题。而JPA则应该使用Criteria API解决这个问题。
对于JOOQ之类的DSL风格框架,最终会被render为参数化的sql,天生免疫sql注入攻击。Ebean也支持DSL方式编程,也一样免疫sql注入攻击。
这是由于DSL风格编程参数化查询比拼接字符串查询更简单,没人会拼接字符串。而jdbc/hql/JPQL拼接字符串有时候比参数化查询更简单,特别是jdbc,不少人会偷懒使用不安全的方式。
05 
JOOQ的失败之处
可能大部分人会不一样意,虽然Hibernate、JPA仍然大行其道,是最主流的持久化框架,但其实这种封装SQL的纯正ORM已通过时,效益低于使用它们的代价,应该淘汰了。
MyBatis虽然有不少优势,但它的优势JOOQ基本上都有,并且多数还更好。MyBatis最大的缺点是难以免写xml文件,xml文件编写困难,容易出错,还不容易查找错误。相对于JOOQ,MyBatis在多数状况下没有任何优点。
Ebean同时具备不少不一样框架的优势,但它是基于JPA的,不免有JPA的各类限制,这是致命的缺点。
JOOQ这个极端轻量级的框架技术上是最完美的,忽然有一天几个Web系统同时崩了,最后发现是JOOQ试用期过时了,这是JOOQ的失败之处,它不是彻底免费的,只是对MySql之类的开源数据库免费。
最终,我决定选择JDBC Template。
    
-END-
若是看到这里,说明你喜欢这篇文章,请 转发、点赞。微信搜索「web_resource」,关注后回复「进群」或者扫描下方二维码便可进入无广告交流群。
扫描二维码进群↓



读 
1.  一份 Spring Boot 项目搭建模板
2.   Spring Boot 实现应用监控和报警
3.  Nginx 从入门到实战
4.  一键式搭建分布式文件服务器
5.  团队开发中 Git 最佳实践
在看 

本文分享自微信公众号 - Java后端(web_resource)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。html

相关文章
相关标签/搜索