当前位置: 首页 > 后端技术 > Java

为什么数据持久化框架放弃了Hibernate、JPA、Mybatis,最终选择了JDBCTemplate!

时间:2023-04-01 18:26:53 Java

因为项目需要选择数据持久化框架,所以看了一下主要流行和冷门的框架。对于复杂的业务系统,最后的结论是JOOQ是整体最好的,可惜它不是完全免费的。选择JDBC模板。Hibernate和Mybatis是使用最多的两个主流框架,而JOOQ、Ebean等小众框架不为很多人所知,但也有很多独特的优势;而JPA是一套Java持久层Api规范,SpringDataJPA是JPARepository的实现。和Hibernate、Mybatis、JOOQ等框架不在一个层次,但是引入SpringDataJPA等框架后,我们会直接使用JPAAPI来查询和更新数据库,就像我们使用Mybatis一样,所以JPA也是与这里的其他框架相比。同样的,JDBC和其他框架是一个级别的,处于所有持久化框架的最底层,但是我们有时候在项目中直接使用JDBC,而SpringJDBCTemplate部分省去了使用JDBC的繁琐细节,降低了使用成本,并且make我们更喜欢在项目中直接使用JDBC。1、SQL封装和性能在使用Hibernate时,我们查询的是POJO实体类,而不是数据库表。比如hql语句selectcount(*)fromUser,里面的User是Java类,不是数据库TableUser。这符合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,我们必须在两个实体类之间添加只是为了连接代码,并且不能被逆向工程。如果表中没有定义外键约束,逆向工程会抹掉我们添加的关联代码。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语句。作为一个基于JPA的框架,Ebean还使用JPQL语言进行查询,这在大多数情况下会很烦人。但是据说Ebean不排斥SQL,可以直接使用SQL查询,也可以使用类似JOOQ的DSL方式在代码中构造SQL语句(或者JPQL语句?),但是我没用过Ebean,所以细节不清楚。JDBCTemplate不用说了,根本不做ORM,当然是纯SQL查询。使用Spring框架,可以结合JDBCTemplate和JPA,在JPA不易查询,或者效率低下不易优化的地方使用JDBC,减轻了Hibernate/JPA封装SQL带来的麻烦,但是我还没有看到SQL的任何封装的必要性除了给程序员带来一大堆麻烦和学习负担之外没有明显的好处。2、DSL和变化适应性为了实现复杂的业务逻辑,无论是使用SQL、hql还是JPQL,我们都不得不编写大量或简单或复杂的查询语句。ORM不能减少这部分工作,最多用另一种面向对象的语言来表达查询需求。如前所述,使用面向对象的语言并不一定比使用SQL更容易。通常业务系统中有很多表,每个表都有很多字段。即使是编写最简单的查询语句也不是一件容易的事。你需要记住数据库中有哪些表和字段,记住哪个函数等。编写查询语句常常成为一个头疼的问题。QueryDSL、JOOQ、Ebean甚至MyBatis和JPA都设计了一些特性来帮助开发者编写查询语句,也有人称之为“DSL风格的数据库编程”。QueryDSL可能是最早实现这种功能的,它将数据库的表结构逆向工程成java类,然后让java程序员用java语法构造复杂的查询语句,并利用IDE的代码自动补全功能,它可以自动提示表名、字段名、查询语句的关键字等,成功地简化了查询语句的编写,减轻了程序员记忆各种名称、函数、关键字的负担。QueryDSL有很多版本,但QueryDSLJPA用的最多,可以帮助开发者编写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给人的印象是复杂难懂。它的MetaModelApi继承了MetaModelAPI+CriteriaAPI的特点,配合HibernateJPA2MetamodelGenerator,给人的感觉有点像QueryDSLJPA,只是弯了个大弯,叠加了好几层技术之后,简洁明了QueryDSLJPA简单易懂的功能几乎没有实现。很多人不推荐使用JPA+QueryDSL,而是推荐使用JPAMetaModelAPI+CriteriaAPI+HibernateJPA2MetamodelGenerator,这个比较难理解,可能是因为这个方案是一个纯标准的JPA方案。数据库DSL编程的另一个主要卖点是它对变化的适应性强。数据库表结构通常在开发过程中经常变化。在传统的非DSL编程中,字段名只是一个字符串。如果字段名或类型发生变化,查询语句不做相应修改,编译不会出错,容易被开发者忽略,是bug的一大来源。在DSL编程中,该字段被反向工程为java类属性。数据库结构改变后,作为java代码一部分的查询语句会出现编译错误,提示开发者修改,可以减少很多bug,减轻测试负担,改进软件。可靠性和质量。3、跨数据库移植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。JDBCTemplate应该是最差的,只能用标准的SQL语句来减少移植的工作量。4.安全性一般来说,拼接查询语句会有安全隐患,容易被SQL注入攻击。无论是jdbc还是hql/JPQL,使用拼接查询语句都是不安全的。对于JDBC,使用参数化的sql语句代替拼接可以解决问题。而JPA应该使用CriteriaAPI来解决这个问题。对于像JOOQ这样的DSL风格的框架,它们最终会被渲染成参数化的SQL,这在本质上是免疫SQL注入攻击的。Ebean也支持DSL编程,同样免疫sql注入攻击。这是因为DSL风格的编程参数化查询比连接字符串查询更容易,而没有人这样做。而且jdbc/hql/JPQL拼接字符串有时比参数化查询更简单,尤其是jdbc,很多人会偷懒,使用不安全的方法。五、JOOQ的失败大多数人可能不同意。虽然Hibernate和JPA依然流行,是最主流的持久化框架,但实际上这种封装SQL的纯ORM已经过时了,使用它们带来的收益低于成本。应该淘汰。MyBatis虽然有很多优点,但是基本都有JOOQ的优点,而且大部分都比较好。MyBatis最大的缺点就是很难避免写xml文件。xml文件写起来难,容易出错,也不容易发现错误。与JOOQ相比,MyBatis在大多数情况下没有优势。Ebean同时具有很多不同框架的优点,但是它是基于JPA的,难免有JPA的各种局限性,这是一个致命的缺点。JOOQ,一个极其轻量级的框架,在技术上是最完美的。突然有一天几个web系统同时崩溃,最后发现JOOQ的试用期已经过期了。这是JOOQ的失败。它不是完全免费的,但是对于像MySql这样的开源数据库是免费的。最终,我决定使用JDBC模板。来源:segmentfault.com/a/1190000018472572