MyBatis还是JPA?终于有答案了

对于一个和数据库打交道的程序员来说,很快会面临着一个艰难的选择。到底是选择MyBatis还是JPA呢?

很多人说,技术选择,都要根据需求来,这个没错。但是,除了需求,还有很重要的一个环节,那就是队友的水平。如果你选择了一些比较高级的技术,那么就是在给整个团队埋坑。

JPA的抽象层次更高,代码写起来也更简洁,但是它一点都不简单。虽然经过了多次的培训,我呆过的几个团队,还是把它用的和屎一样。

我扔掉了JPA

我仔细想了一下,有下面几点原因,造成了JPA在很多团队根本就玩不下去。

  • JPA适合业务模型固定的场景,适合比较稳定的需求。但是国内这种朝三暮四的需求风格,产品经理这种传话筒式的设计模式,造成了需求的泛滥和不确定。JPA在这种模式下就是渣。
  • JPA的技术要求比较高。不要怀疑,你刚开始用起里可能觉得非常简单。但随着你的深入使用,你会发现这是一个灾难。里面的各种转换和缓存,会把人绕晕。而大多数的快餐程序员是不想要了解这些的。
  • 很多程序员很会写SQL,所以很多SQL语句长的很胖,长的要命。业务混乱,多张表关联,我甚至见过上百张业务表关联的复杂业务。DBA无奈之下,通常都会有sql审核。JPA搞sql审核?还是弱了一点。

所以,不是JPA不好,而是它不符合国情而已。想要在公司内推行JPA,你需要给我一个稳定的产品团队、一个牛X的技术团队才行。

所以,大多数公司宁可写一堆重复的、乱七八糟的Mybaits代码,也不会轻易尝试JPA,这是符合逻辑的,符合事物发展规律的。

所以,我们下面的文章就是来讨论MyBatis的,来看一下Mybaits到底要怎么写才算优雅。

MyBatis为什么不好用

优秀的程序员都是很懒的。所以很多人不想设计实体的sql。JPA可以直接根据Java的实体代码,生成sql的库表,这在使用Mybatis的人来看,是非常羡慕的。

使用MyBatis,要倒着来。需要先设计库表,然后根据库表反向生成一堆Java代码和配置文件。

这个代码生成器,就是mybatis-generator。

但是,请注意。这个生成器生成的代码,有四种模式!!!这就是最让初学者难受的地方。如果你也是刚接触MyBatis,强烈推荐只关注下面第一种模式。

  • MyBatis3 这种模式就是我们常用的方式,会生成domain类、Example类、mapper映射文件等。它生成的信息比较啰嗦,内容几乎无法改动。对于项目中自己写的sql,一般都采用手写的方式再写一份,而不是改动原来的文件。
  • MyBatis3Simple 上面这种模式的简易代码生成模式,缺少一些东西,但很简洁。对MyBatis没有经验,不推荐使用它。
  • MyBatis3DynamicSql 这是通过Builder模式实现的动态SQL特性,你还需要加入额外的jar包。加上它之后,其实和JPA是有点相似的。既然如此,那为何不直接使用JPA呢?所以这个DSQL虽然是默认的生成行为,但是非常不推荐。
  • MyBatis3Kotlin 这个不废话。就是生成Kotlin版的一些配置和代码信息。

所以,下面仅仅介绍MyBatis3模式的代码生成。

要使用它,需要在pom.xml里加入它的依赖。

<dependency>
  <groupId>org.mybatis.generator</groupId>
  <artifactId>mybatis-generator-core</artifactId>
  <optional>true</optional>
  <scope>test</scope>
  <version>1.4.0</version>
</dependency>

我个人喜欢使用Java代码来操作代码生成这个过程,所以下面就是生成代码的代码。

public class MBGTool {
  public static void main(String[] args) throws Exception {
    List<String> warnings = new ArrayList<>();
    boolean overwrite = true;
    InputStream configFile = MBGTool.class.getResourceAsStream("/generator/generatorConfig.xml");
    ConfigurationParser cp = new ConfigurationParser(warnings);
    Configuration config = cp.parseConfiguration(configFile);
    DefaultShellCallback callback = new DefaultShellCallback(overwrite);
    MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
    myBatisGenerator.generate(null);
  }
}

从代码中,我们可以看到需要配置一个generatorConfig.xml文件,用来规定怎么生成代码文件。

<!DOCTYPE generatorConfiguration PUBLIC
    "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
    "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
  <context id="simple" targetRuntime="MyBatis3">
    <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
            connectionURL="jdbc:mysql://localhost:3306/mbye"
            userId="root"
            password="root"
    />
    <javaModelGenerator targetPackage="com.github.javarunfast.mbye.domain" targetProject="src/main/java">
      <property name="enableSubPackages" value="true"/>
      <property name="trimStrings" value="true"/>
    </javaModelGenerator>
    <sqlMapGenerator targetPackage="com.github.javarunfast.mbye.mapper" targetProject="src/main/resources"/>
    <javaClientGenerator type="XMLMAPPER" targetPackage="com.github.javarunfast.mbye.mapper" targetProject="src/main/java">
      <property name="enableSubPackages" value="true"/>
    </javaClientGenerator>
    <table tableName="test"/>
  </context>
</generatorConfiguration>

运行我们的MBGTool文件之后,就可以生成MyBatis的代码了。

怎么写代码最优雅

但是,我这里并不是要推荐你使用这种模式。因为,它生成了一大堆无用的文件。假如你的项目使用了sonar这样的代码质量审查工具,你会发现很多飘红的地方,还有那要命的覆盖率问题。
怎么办?

经过我多年的摸索,我现在推荐一种非常好用的写法。自从我采用了这种方式之后,就再也没有换过。

第一、不需要代码生成器了
数据表的设计,还有domain的书写,全部靠手工。这样我们的代码,如果有必要,还可以迁移到JPA上去。这种模式还能顺便学习一下Java里面的数据类型,是如何和SQL里的数据类型一一对应的。在做表设计的时候,顺便能够了解一些背后的原理。

第二、不需要写映射文件了
生成器生成的东西,确实是有一堆无用的逻辑。比如我的某个数据表,根本不需要提供查询所有和删除这种动作,它还是默认提供了。

在这种简约模式下,我们直接手写Mapper文件,然后只声明所需要的接口方法就可以了。

@Mapper
public interface AccountBasicMapper {
  @Insert("AccountBasicMapper/insert.sql")
  void insert(@Param("r") AccountBasic record);
}

可以看到,里面有一个Insert注解,我们传入了一个具体的domain,然后,就可以在AccountBasicMapper目录下的insert.sql文件里,书写具体的sql语句了。

sql语句样例如下:

INSERT INTO account_basic(
  account_id,
  nick_name,
  password,
  sex,
  state,
  photo_url,
  created,
  modified,
  version
)VALUES (
  <@p name="r.accountId"/>,
  <@p name="r.nickName"/>,
  <@p name="r.password"/>,
  <@p name="r.sex"/>,
  <@p name="r.state"/>,
  <@p name="r.photoUrl"/>,
  <@p name="r.created"/>,
  <@p name="r.modified"/>,
  <@p name="r.version"/>
)

那么这是什么语法呢?它又是如何知道是这样配置的呢?这就需要引入MyBatis的脚本语言配置功能。在这里,我们使用的freemark的模版。

不要忘了加入它的依赖。

<dependency>
  <groupId>org.mybatis.scripting</groupId>
  <artifactId>mybatis-freemarker</artifactId>
  <version>1.2.2</version>
</dependency>

然后,在yaml文件里做上相应的配置就ok了。

mybatis:
 check_config_location: false
 scripting-language-driver:
  freemarker:
   template-file:
    base-dir: mappers/
   path-provider:
    includes-package-path: false
    separate-directory-per-mapper: false

这种方式的好处和坏处

我个人是非常喜欢这种模式的。因为它有下面几个好处:

  • 用什么写什么,代码量少,简洁优雅。
  • SQL集中,不用分散在代码里,xml里,或者注解里。方便DBA进行SQL审核。由于没了xml的干扰,SQL反而更加简洁了。
  • 一个DAO方法一个sql文件,模式单一可控。
  • MyBatis的功能优势可以全部发挥,无缝集成。

当然,缺点也是显而易见的。

  • 即使变了个参数,也要修改很多sql文件。
  • 需要为每一个方法配一个sql文件,即使这是个很弱智的插入查询方法。

不过,我并不认为这是个问题。每一个方法配备一个sql文件,代码写起来反而更加简单了。当出现问题的时候,也不用根据逻辑进行跟踪定位到拼接后的SQL语句。我现在,只需要拿到对应方法的SQL文件,就可以改吧改吧,直接在sql终端里执行调试。这样,sql优化也变的简单了。

当然,一个人一个习惯。我个人喜欢这种模式,而且在我的团队里推行这种模式,发现运行的也很好。另外,程序员为了少写重复的sql代码,在设计Dao接口的时候,反而更加认真了。

这可能是一个额外的收获吧。

到此这篇关于MyBatis还是JPA?终于有答案了的文章就介绍到这了,更多相关MyBatis还是JPA内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring jpa和mybatis整合遇到的问题解析

    前一阵子接手了一个使用SpringBoot 和spring-data-jpa开发的项目,后期新加入一个小伙伴,表示jpa相比mybatis太难用,多表联合的查询写起来也比较费劲,所以便加入了mybatis的支持 开始的时候 @Configuration @EnableJpaRepositories("com.xxx.xxx.repository") class JpaConfig 使用这种方式去配置的jpa,遇到一个问题,就是能select 但是不能save,所以就修改为配置文件的方式

  • springboot整合Mybatis、JPA、Redis的示例代码

    引言 在springboot 项目中,我们是用ORM 框架来操作数据库变的非常方便.下面我们分别整合mysql ,spring data jpa 以及redis .让我们感受下快车道. 我们首先创建一个springboot 项目,创建好之后,我们来一步步的实践. 使用mybatis 引入依赖: <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-

  • MyBatis还是JPA?终于有答案了

    对于一个和数据库打交道的程序员来说,很快会面临着一个艰难的选择.到底是选择MyBatis还是JPA呢? 很多人说,技术选择,都要根据需求来,这个没错.但是,除了需求,还有很重要的一个环节,那就是队友的水平.如果你选择了一些比较高级的技术,那么就是在给整个团队埋坑. JPA的抽象层次更高,代码写起来也更简洁,但是它一点都不简单.虽然经过了多次的培训,我呆过的几个团队,还是把它用的和屎一样. 我扔掉了JPA 我仔细想了一下,有下面几点原因,造成了JPA在很多团队根本就玩不下去. JPA适合业务模型固

  • Mybatis与Jpa的区别和性能对比总结

    前言 这几天听朋友说JPA很好用,根本不用写sql.我在想一个程序员不写sql还能叫程序员?而且越高级的工具封装越多的工具,可拓展性和效率就非常的低,况且我本身非常不喜欢过于封装的东西,平时喜欢手写sql,所以一直都是用mybatis去写业务.然后发现jpa的saveAll()批量插入批量更新速度太慢了,导致一些用excel导入的一些东西非常慢,弄得原本同步可以解决的事情每次导入都要开启一个异步,个人感觉这种做法非常不好.因为异步其实就是对当前的业务不影响去另外的时间段去做,例如跑定时任务,异步

  • 关于Mybatis与JPA的优缺点说明

    目录 Mybatis与JPA的优缺点 JPA java持久层API JPA优势 Mybatis优点 Mybatis缺点 JPA与Mybatis的区别 JPA就是把mapper层的接口换成repository的接口 JPA的repository Mybatis与JPA的优缺点 JPA java持久层API 可理解为一种规范,Hibernate就是其具体一个实现.它的实现应用是Spring DataJpa,Spring提供了一套简化开发框架,按照约定好的方法命名规则,编写dao层接口,即可在不编写实

  • 详解SpringBoot是如何整合JPA的

    目录 SpringBoot整合JPA JPA & Spring Data JPA Hibernate & JPA Hibernate VS Mybatis 一.导入依赖 二.简单的CRUD 2.1 配置文件 2.2 实体类 2.3 Dao层 2.4 service层 2.5 controller 三.自定义SQL 四.分页查询 五.连表查询 六.分组查询 七.与mybatis对比 SpringBoot整合JPA JPA & Spring Data JPA JPA是Java Pers

  • Springboot使用Spring Data JPA实现数据库操作

    SpringBoot整合JPA 使用数据库是开发基本应用的基础,借助于开发框架,我们已经不用编写原始的访问数据库的代码,也不用调用JDBC(Java Data Base Connectivity)或者连接池等诸如此类的被称作底层的代码,我们将从更高的层次上访问数据库,这在Springboot中更是如此,本章我们将详细介绍在Springboot中使用 Spring Data JPA 来实现对数据库的操作. JPA & Spring Data JPA JPA是Java Persistence API

  • 轻松搞定SpringBoot JPA使用配置过程详解

    SpringBoot整合JPA 使用数据库是开发基本应用的基础,借助于开发框架,我们已经不用编写原始的访问数据库的代码,也不用调用JDBC(Java Data Base Connectivity)或者连接池等诸如此类的被称作底层的代码,我们将从更高的层次上访问数据库,这在Springboot中更是如此,本章我们将详细介绍在Springboot中使用 Spring Data JPA 来实现对数据库的操作. JPA & Spring Data JPA JPA是Java Persistence API

  • Java Fluent Mybatis实战之构建项目与代码生成篇上

    目录 简述 特性 项目搭建 maven依赖引入-fluent-mybatis 表构建 代码生成工具类 解决类找不到问题 总结 简述 偶然看到一篇关于阿里新orm框架的文章,好奇的点了进去.开发后端多年,看到这个还是有点兴奋的.常用mysql的orm框架mybatis.jpa,到后来的优化框架mybatis-plus都是用过,他们或多或少都有优缺点吧.程序员本就是日常革新技术的职业,所以了解更多的框架绝对不会有错误.所以我尝试着把自己学习该框架的过程,记录下来,尽可能去掉一些项目工程中用不到的功能

  • Mybatis执行插入语句后并返回主键ID问题

    目录 1.MySQL数据库设置ID自增情况 2.使用UUID自增主键 3.mybatis-plus在执行插入语句后返回自定义ID 总结 我们知道JDBC可以实现插入语句后返回主键Id,那mybatis可以实现吗? 答案是肯定的. 1.MySQL数据库设置ID自增情况 <insert id="insertUser" parameterType="com.crush.mybatisplus.entity.User"> INSERT INTO tb_user

  • SQL SERVER 2005 最小安装经验

    最后重装好N次都没有发现VS2005的选项,但这东西在安装后确实存在. 再一个问题就是装一个数据库得花这么长时间,又占空间,装出来后很多工具都没有使用过的.能否只安装我最需要的数据库服务器和必要的管理工具?就这个问题今天终于找到答案. 问题一"VS2005是怎么装上去的" 安装SQL时选了下面的商业开发工具造成:SQL Server Business Intelligence Development Studio,把这个勾去掉就不会安装VS2005了. 问题二"装个最小的SQ

随机推荐