fluent-mybatis入门

1. 引子

mybatis作为传统的数据库映射框架相比JPA要灵活的多,但是使用xml方式过于繁琐,使用注解会简单一些,但是仍要在mapper接口中的注解中编写sql,不是太方便,而且IDE没有语法检查,出错的概率很大。

Mybatis Plus将jpa和mybatis进行了整合,取各自的优点,使用wapper来构造sql,十分方便灵活,目前是大多数项目的首选。但是在wapper构造sql的时候需要对数据库表的字段名进行魔法值编写,并不十分优雅,无法做到将生成的entity类完全利用。

那有没有一个框架可以实现简单、方便、灵活、快速、优雅的操作数据库呢?有的,就是我要吹爆的 FluentMybatis

顾名思义是对mybatis的框架的修改,fluent是流式的意思,即使用流式编程的方式来使用mybatis。

2.FluentMybatis官方介绍

在这里插入图片描述

  • No XML, No Mapper, No If else, No String魔法值编码

  • 只需Entity就实现强大的FluentAPI: 支持分页, 嵌套查询, AND OR组合, 聚合函数…

3.简单增删改查

引入依赖

maven:

<properties>
    <fluent-mybatis.version>1.6.14</fluent-mybatis.version>
</properties>
<dependencies>
    <!-- 引入fluent-mybatis 运行依赖包, scope为compile -->
    <dependency>
        <groupId>com.github.atool</groupId>
        <artifactId>fluent-mybatis</artifactId>
        <version>${fluent-mybatis.version}</version>
    </dependency>
    <!-- 引入fluent-mybatis-processor, scope设置为provider 编译需要,运行时不需要 -->
    <dependency>
        <groupId>com.github.atool</groupId>
        <artifactId>fluent-mybatis-processor</artifactId>
        <scope>provided</scope>
        <version>${fluent-mybatis.version}</version>
    </dependency>
</dependencies>

其中fluent-mybatis是fluent-mybatis运行时的正主,需要设置为compile级别
而fluent-mybatis-processor是编译时,根据Entity文件生成一系列辅助类的处理器,依赖级别为provided就可以。

gradle:

buildscript {
    ext {
        lombokVersion = '1.18.8'
        fluentMybatisVersion = '1.6.14'
        springVersion = '5.3.7'
    }
}
plugins {
    id 'net.ltgt.apt' version '0.21'
}

subprojects {
    apply plugin: 'net.ltgt.apt-idea'
    apply plugin: 'net.ltgt.apt-eclipse'

    sourceCompatibility = 1.8
    targetCompatibility = 1.8
    dependencies {
        compile("com.github.atool:fluent-mybatis:${fluentMybatisVersion}")
        compileOnly("org.projectlombok:lombok:${lombokVersion}")
        compileOnly("com.github.atool:fluent-mybatis-processor:${fluentMybatisVersion}")

        // annotation processor配置
        annotationProcessor("org.projectlombok:lombok:${lombokVersion}")
        annotationProcessor("com.github.atool:fluent-mybatis-processor:${fluentMybatisVersion}")
    }
}

创建数据库

建立一个用户表sys_user:

DROP TABLE IF EXISTS `sys_user`;

CREATE TABLE `sys_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `account` varchar(50) NOT NULL COMMENT '账号',
  `describe` varchar(100) DEFAULT NULL COMMENT '描述',
  `nick_name` varchar(50) DEFAULT NULL COMMENT '昵称',
  `phone` varchar(20) DEFAULT NULL COMMENT '手机号',
  `email` varchar(50) DEFAULT NULL COMMENT '邮箱',
  `state` int(4) NOT NULL DEFAULT 0 COMMENT '状态0正常',
  `avatar_url` varchar(200) DEFAULT NULL COMMENT '头像url',
  `created_time` datetime NOT NULL COMMENT '创建时间',
  `modified_time` datetime DEFAULT NULL COMMENT '修改时间',
  `del_flag` int(4) NOT NULL DEFAULT 0 COMMENT '删除标记',
  PRIMARY KEY (`id`),
  UNIQUE KEY `unique_sys_user_account` (`account`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;

编写代码

创建一个springboot工程:

启动类和mybatis一样新增一个@MapperScan,但是扫描的mapper包不需要创建。

@SpringBootApplication
@MapperScan("com.example.fluent.mapper")
public class FluentMybatisApplication {

    public static void main(String[] args) {
        SpringApplication.run(FluentMybatisApplication.class, args);
    }

}

创建一个实体类,也可以生成出来。

@FluentMybatis
@Data
@Builder
public class SysUser implements IEntity {

    private Long id;

    private String account;

    private String describe;

    private String nickName;

    private String phone;

    private String email;

    private Integer state;

    private String avatarUrl;

    private LocalDateTime createdTime;

    private LocalDateTime modifiedTime;

    private Integer delFlag;

    @Tolerate
    public SysUser(){}
}

配置数据库连接:

server.servlet.context-path=/test
server.port=8080

spring.datasource.url=jdbc:mysql://127.0.0.1/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

编译项目生成实体类对应的mapper、dao等文件,这一步和其他框架有所不同。

在这里插入图片描述

生成的class在target中,代码里面可以直接使用。

在这里插入图片描述

这些生成的文件熟悉mybatis的都知道有什么作用了。启动类里面的mapper也是对应这里的包。

编写数据库操作代码,比较简单直接写在controller里面:

@RestController
public class WebController {
    
    @Resource
    private SysUserMapper sysUserMapper;

    /**
     * 使用id查询
     * @param id
     * @return
     */
    @GetMapping("queryById")
    public String queryById(Long id) {
        SysUser sysUser = sysUserMapper.findOne(sysUserMapper
                .query()
                .where
                .id()
                .eq(id)
                .end()
        );
        System.out.println(sysUser.getAccount());
        return "ok";
    }

    /**
     * 保存
     * @return
     */
    @GetMapping("save")
    public String save() {
        sysUserMapper.insert(SysUser.builder()
                .account("aaa" + System.currentTimeMillis())
                .createdTime(LocalDateTime.now())
                .delFlag(0)
                .describe("13131")
                .state(0)
                .build());
        return "ok";
    }

    /**
     * 更新
     * @param id
     * @param describe
     * @return
     */
    @GetMapping("update")
    public String update(Long id, String describe) {
        sysUserMapper.updateBy(sysUserMapper.updater().set.describe().is(describe).end()
                .where.id().eq(id).end());
        return "ok";
    }

    /**
     * 删除
     * @param id
     * @return
     */
    @GetMapping("delete")
    public String delete(Long id) {
        sysUserMapper.delete(sysUserMapper.query().where.id().eq(id).end());
        return "ok";
    }

}

通过例子可以看出,fluent-mybatis很简单的就可以完成单表的操作,无需sql、xml,和mapper,只需要一个实体类,然鹅这个实体类还是可以生成的!

直接看代码就能看出来框架将sql语句中的语法映射到代码中,其实就是类似dsl对象化的方式。很多习惯了xml或者注解直出sql方式的人会认为这种不伦不类,直接sql不好吗?或者jpa大神会说——就这,知道什么是DDD吗?

其实还是没有使用习惯的,当你是mybatis-plus用户或者习惯了在代码方式流式写sql语句你就会觉得——真香!

在这里插入图片描述

对生成文件的解析

  • 核心接口类, 使用时需要了解
  1. mapper/*Mapper: mybatis的Mapper定义接口, 定义了一系列通用的数据操作接口方法。
  2. dao/*BaseDao: Dao实现基类, 所有的DaoImpl都继承各自基类 根据分层编码的原则,我们不会在Service类中直接使用Mapper类,而是引用Dao类。我们在Dao实现类中根据条件实现具体的数据操作方法。
  3. wrapper/*Query: fluent mybatis核心类, 用来进行动态sql的构造, 进行条件查询。
  4. wrapper/*Updater: fluent mybatis核心类, 用来动态构造update语句。
  5. entity/*EntityHelper: Entity帮助类, 实现了Entity和Map的转换方法
  • 辅助实现时, 实现fluent mybatis动态sql拼装和fluent api时内部用到的类,使用时无需了解 在使用上,我们主要会接触到上述5个生成的java类。Fluent Mybatis为了实现动态拼接和Fluent API功能,还生成了一系列辅助类。
  1. helper/*Mapping: 表字段和Entity属性映射定义类
  2. helper/*SqlProviderP: Mapper接口动态sql提供者
  3. helper/*WrapperHelper: Query和Updater具体功能实现, 包含几个实现:select, where, group by, having by, order by, limit

mapper类中生成的基本上包含所有要使用的方法。

在这里插入图片描述

当然有人会说这是单表操作,如果复杂查询,多变关联,分组、函数等等呢?别急这些可都是mybatis的特长,所有fluent也会有完美的解决方式,会在后面的文章中写道。

4.和其他框架对比

-Mybatis PlusFluent Mybatis
代码生成生成 Entity, Mapper, Wrapper等文件, 并且Generator很好用只生成Entity, 再通过编译生成 Mapper, Query, Update 和 SqlProvider
和Mybatis的共生关系需要替换原有的SqlSessionFactoryBean对Mybatis没有任何修改,原来怎么用还是怎么用
动态SQL构造方式应用启动时, 根据Entity注解信息构造动态xml片段,注入到Mybatis解析器应用编译时,根据Entity注解,编译生成对应方法的SqlProvider,利用mybatis的Mapper上@InsertProvider @SelectProvider @UpdateProvider注解关联
动态SQL结果是否容易DEBUG跟踪不容易debug容易,直接定位到SQLProvider方法上,设置断点即可
动态SQL构造通过硬编码字段名称, 或者利用Entity的get方法的lambda表达式通过编译手段生成对应的方法名,直接调用方法即可
字段变更后的错误发现通过get方法的lambda表达的可以编译发现,通过字段编码的无法编译发现编译时便可发现
不同字段动态SQL构造方法通过接口参数方式通过接口名称方式, FluentAPI的编码效率更高
语法渲染特点通过关键变量select, update, set, and, or可以利用IDE语法渲染, 可读性更高

主要和mybatis-plus对比,两者并不存在哪个更好,哪个不好。基本上都是对mybatis的增强,如果你比较懒就阔以选择fluent-mybatis。

至于jpa,喜欢的都喜欢,不喜欢的怎么都不喜欢,各取所需吧。

5.参考文档

官方文档: https://gitee.com/fluent-mybatis/fluent-mybatis-docs

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐