再见 MyBatis!我选择 JDBCTemplate!

这篇博客深入比较了JOOQ、Hibernate、MyBatis等数据持久化框架。JOOQ虽然在复杂业务中表现出色,但非完全免费。Hibernate和JPA通过ORM封装SQL,但性能和灵活性受限。MyBatis以其简洁和高性能受到青睐。JDBC作为底层框架,有时也被直接使用。JDBCTemplate简化了JDBC的使用。DSL编程方面,JOOQ提供了强大的SQL构造能力,并在跨数据库移植和安全性上有优势。作者最终选择了JDBCTemplate。

因为项目需要选择数据持久化框架,看了一下主要几个流行的和不流行的框架,对于复杂业务系统,最终的结论是,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。

一、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的必要性,除了给程序员带来一大堆麻烦和学习负担之外,没有太明显的好处。

二、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,减轻测试的负担,提高软件的可靠性和质量。

三、跨数据库移植

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语句来减少移植工作量。

四、安全性

一般来说,拼接查询语句都会有安全隐患,容易被sql注入攻击。不论是jdbc,还是hql/JPQL,只要使用拼接的查询语句都是不安全的。对于JDBC来说,使用参数化的sql语句代替拼接,可以解决问题。而JPA则应该使用Criteria API解决这个问题。

对于JOOQ之类的DSL风格框架,最终会被render为参数化的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 Template。

来源:segmentfault.com/a/1190000018472572

欢迎关注
<think>嗯,用户现在想了解MyBatis是否封装了JdbcTemplate以及DataSourceBuilder.create().build()指定数据源的方式。首先,我需要回顾一下之前用户的问题和之前的回答。之前讨论的是Spring Boot中如何配置数据源,特别是使用DataSourceBuilder来创建数据源,以及多数据源的配置方法。现在用户进一步询问MyBatis是否涉及这些组件,需要明确两者的关系。 首先,用户的问题分为两部分:MyBatis是否封装了JdbcTemplate,以及DataSourceBuilder的使用方法在MyBatis中如何应用。根据引用中的信息,JdbcTemplate是Spring框架对JDBC的封装,而MyBatis是一个持久层框架,使用不同的方式操作数据库,比如通过映射文件和接口。因此,需要明确MyBatisJdbcTemplate是两个不同的工具,各自有不同的实现方式,但可能在某些情况下结合使用。 接着,关于DataSourceBuilder,用户之前的问题已经详细说明了如何在Spring Boot中使用它来配置数据源,包括自动类型推断和多数据源配置。现在需要解释在MyBatis中是否使用同样的方式指定数据源。通常,MyBatis-Spring整合时会使用Spring管理的数据源,因此DataSourceBuilder创建的数据源可以被MyBatis使用,这一点需要说明。 另外,引用中提到MyBatis的优缺点,比如SQL硬编码问题,这可能与JdbcTemplate的缺点类似,但MyBatis通过XML或注解配置SQL,避免了硬编码。需要指出两者的不同之处,以及MyBatis如何封装JDBC而不是JdbcTemplate。 可能用户混淆了这两个框架的关系,认为MyBatis可能基于JdbcTemplate构建,但实际上它们是独立的。需要明确MyBatisJdbcTemplate都是对JDBC的封装,但层次和方式不同。MyBatis更关注于ORM和SQL管理,而JdbcTemplate是更底层的模板方法。 关于数据源的指定,MyBatis通常依赖于外部数据源配置,比如通过Spring的DataSource,因此在整合Spring和MyBatis时,使用DataSourceBuilder创建的数据源是可行的。需要说明MyBatis如何通过配置使用这些数据源,例如在MyBatis的配置文件中引用Spring管理的Bean。 总结起来,回答需要分两部分:MyBatis是否封装JdbcTemplate,答案是否定的,两者是独立的不同层级的封装;DataSourceBuilder在MyBatis中的使用方式,即通过Spring配置数据源,然后MyBatis使用该数据源。同时,结合用户提供的引用内容,特别是引用2中关于JdbcTemplateMyBatis的描述,以及引用3中的数据源配置示例,来支持回答的正确性。 需要确保回答结构清晰,分点说明,并引用相关的引用内容作为依据。同时,用户可能想知道如何在MyBatis项目中配置数据源,是否同样使用DataSourceBuilder,这点需要详细说明,可能给出配置示例。此外,用户可能对两者的整合方式感兴趣,比如在Spring Boot项目中同时使用MyBatisJdbcTemplate的情况,但根据引用1中的条件,需要注意避免重复创建JdbcTemplate的情况,这可能需要进一步解释。 最后,用户的问题可能隐含了对框架选择的理解,需要明确MyBatisJdbcTemplate的适用场景,帮助用户更好地决策。同时,确保回答准确,引用正确,符合用户之前的讨论内容。</think>### 回答:MyBatisJdbcTemplate 的关系及数据源配置方式 --- #### **一、MyBatis 是否封装了 JdbcTemplate?** **否**。MyBatisJdbcTemplate 是两种独立的 JDBC 封装方案,它们的实现目标和设计理念不同: 1. **JdbcTemplate 的特点** - **定位**:Spring 框架提供的轻量级 JDBC 封装工具,通过模板方法简化 JDBC 操作(如资源管理、异常处理)[^2]。 - **使用方式**:直接执行 SQL 语句,通过 `update()` 和 `query()` 等方法操作数据库。 - **缺点**:SQL 硬编码在 Java 代码中,维护性较差[^2]。 2. **MyBatis 的特点** - **定位**:ORM(对象关系映射)框架,专注于 SQL 与对象映射的灵活性。 - **实现方式**:通过 XML 或注解定义 SQL,将结果自动映射为 Java 对象,**直接基于原生 JDBC 驱动**,不依赖 JdbcTemplate[^2]。 - **优点**:解耦 SQL 与业务代码,支持动态 SQL 和复杂查询。 **总结**: MyBatis 并未封装 JdbcTemplate,两者是同一层级(对 JDBC 的封装)的不同实现。开发者可根据需求选择: - **JdbcTemplate**:适合简单、少量 SQL 的场景。 - **MyBatis**:适合需要 SQL 灵活管理、对象映射的场景。 --- #### **二、MyBatis 中如何指定数据源?** MyBatis 本身不管理数据源,**数据源的创建和配置由 Spring 完成**。在 Spring Boot 中,`DataSourceBuilder.create().build()` 是 Spring 提供的数据源构建工具,MyBatis 通过以下方式集成: ##### **1. 单数据源配置** ```yaml # application.yml spring: datasource: url: jdbc:mysql://localhost:3306/mydb username: root password: 123456 driver-class-name: com.mysql.cj.jdbc.Driver ``` MyBatis 自动使用 Spring 管理的默认数据源,无需额外配置。 ##### **2. 多数据源配置** 若需多数据源,需显式定义 `DataSource` Bean 并绑定 MyBatis 到指定数据源: ```java @Configuration public class DataSourceConfig { // 主数据源(绑定到 MyBatis) @Bean @ConfigurationProperties("spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } // MyBatis 配置(指向主数据源) @Bean public SqlSessionFactory sqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSource); return sessionFactory.getObject(); } } ``` --- #### **三、`DataSourceBuilder` 在 MyBatis 中的使用** 在 Spring Boot 整合 MyBatis 的场景中,`DataSourceBuilder` 的作用与普通 Spring 项目一致: 1. **自动推断连接池类型** 根据依赖自动选择 HikariCP、Tomcat JDBC 等连接池[^3]。 2. **配置绑定** 通过 `@ConfigurationProperties` 从配置文件中注入属性(如 URL、用户名)[^3]。 --- #### **四、关键区别总结** | 特性 | JdbcTemplate | MyBatis | |---------------------|----------------------|------------------------| | **SQL 管理** | 硬编码在 Java 代码中 | 通过 XML/注解解耦 | | **对象映射** | 手动处理结果集 | 自动映射为 Java 对象 | | **数据源依赖** | 需 Spring 提供 | 需 Spring 提供 | | **适用场景** | 简单 CRUD 操作 | 复杂 SQL 和对象映射需求 | --- ### 相关问题 1. **MyBatisJdbcTemplate 在事务管理上有何差异?** 2. **如何在 MyBatis 中动态切换多数据源?** 3. **Spring Boot 如何自动配置 MyBatis 与数据源的关联?**
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值