Fluent mybatis

简介: 众多框架都是从无到有,从有到简的一个过程,核心理念都是为简化开发为生。

1.背景

众多框架都是从无到有,从有到简的一个过程,核心理念都是为简化开发为生。

像Spring这样延续至今的佼佼者,也逐渐摒弃XML,向代码化配置的方式发展。在这方面,iBatis一直是个保守派,即使在MyBatis接过iBatis的衣钵之后,也只是”重磅“推出了支持代码执行SQL的@Select/@Insert/@Update/@Delete注解(以及相应的4种Provider注解),用来抵挡开发者们对XML泛滥的吐槽,但是使用注解也存在一些问题,比如说代码可读性插,可复用性差等等。这时候孕育出一大批基于mybatis加强的orm框架,例如mybatis-plus,tk-mybatis等等。

mybatis-plus的人气比tk-mybatis高很多,原因我个人觉得有两个:

但是以上两个都不是我今天讲的主角,今天主角是 Fluent-Mybatis: 基于mybatis但青出于蓝而胜于蓝

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

img

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用

Github地址https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公众号Shepherd进阶笔记

2.实现原理

使用fluent-mybatis非常简单:

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

引入依赖之后我们只需要编写entity实现类信息即可。然后通过编译会生成对应的mapper接口类供我们使用,其实现原理如下图所示:

FluentMybatis原理

  • 核心接口类, 使用时需要了解
  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

3.动态sql的实现

我们通过一个比较典型的业务需求来具体实现和对比下,假如有学生成绩表结构如下:

create table `student_score`
(
    id           bigint auto_increment comment '主键ID' primary key,
    student_id   bigint            not null comment '学号',
    gender_man   tinyint default 0 not null comment '性别, 0:女; 1:男',
    school_term  int               null comment '学期',
    subject      varchar(30)       null comment '学科',
    score        int               null comment '成绩',
    gmt_create   datetime          not null comment '记录创建时间',
    gmt_modified datetime          not null comment '记录最后修改时间',
    is_deleted   tinyint default 0 not null comment '逻辑删除标识'
) engine = InnoDB default charset=utf8;

现在有需求:

「统计 2000 年三门学科('英语', '数学', '语文')及格分数按学期,学科统计最低分,最高分和平均分, 且样本数需要大于 1 条,统计结果按学期和学科排序」

我们可以写 SQL 语句如下

select school_term,
       subject,
       count(score) as count,
       min(score)   as min_score,
       max(score)   as max_score,
       avg(score)   as avg_score
from student_score
where school_term >= 2000
  and subject in ('英语', '数学', '语文')
  and score >= 60
  and is_deleted = 0
group by school_term, subject
having count(score) > 1
order by school_term, subject;

那上面的需求,分别用fluent mybatis, 原生mybatisMybatis plus来实现一番。

使用fluent mybatis 来实现上面的功能

图片

需要本文具体演示代码可加我微信:codedq,免费获取!

我们可以看到fluent api的能力,以及 IDE 对代码的渲染效果。

换成mybatis原生实现效果

定义Mapper接口

public interface MyStudentScoreMapper {
   
   
    List<Map<String, Object>> summaryScore(SummaryQuery paras);
}

定义接口需要用到的参数实体 SummaryQuery

@Data
@Accessors(chain = true)
public class SummaryQuery {
   
   
    private Integer schoolTerm;

    private List<String> subjects;

    private Integer score;

    private Integer minCount;
}

定义实现业务逻辑的mapper xml文件

<select id="summaryScore" resultType="map" parameterType="cn.org.fluent.mybatis.springboot.demo.mapper.SummaryQuery">
    select school_term,
    subject,
    count(score) as count,
    min(score) as min_score,
    max(score) as max_score,
    avg(score) as max_score
    from student_score
    where school_term >= #{schoolTerm}
    and subject in
    <foreach collection="subjects" item="item" open="(" close=")" separator=",">
        #{item}
    </foreach>
    and score >= #{score}
    and is_deleted = 0
    group by school_term, subject
    having count(score) > #{minCount}
    order by school_term, subject
</select>

实现业务接口(这里是测试类,实际应用中应该对应 Dao 类)

@RunWith(SpringRunner.class)
@SpringBootTest(classes = QuickStartApplication.class)
public class MybatisDemo {
   
   
    @Autowired
    private MyStudentScoreMapper mapper;

    @Test
    public void mybatis_demo() {
   
   
        // 构造查询参数
        SummaryQuery paras = new SummaryQuery()
            .setSchoolTerm(2000)
            .setSubjects(Arrays.asList("英语", "数学", "语文"))
            .setScore(60)
            .setMinCount(1);

        List<Map<String, Object>> summary = mapper.summaryScore(paras);
        System.out.println(summary);
    }
}

总之,直接使用 mybatis,实现步骤还是相当的繁琐,效率太低。那换成mybatis plus的效果怎样呢?

换成mybatis plus实现效果

mybatis plus的实现比mybatis会简单比较多,实现效果如下

图片

如红框圈出的,写mybatis plus实现用到了比较多字符串的硬编码(可以用 Entity 的 get lambda 方法部分代替字符串编码)。字符串的硬编码,会给开发同学造成不小的使用门槛,个人觉得主要有 2 点:

  1. 字段名称的记忆和敲码困难
  2. Entity 属性跟随数据库字段发生变更后的运行时错误

fluent-mybatis实现动态sql原理

Fluent Mybatis构造动态SQL语句的方式是直接使用mybatis3中的SQLProvider功能。

@SelectProvider, @UpdateProvider, @InsertProvider, @DeleteProvider 这些Provider是声明在Mapper接口类上的, 比如你定义了一个YourEntity实体类, fluent mybatis在编译时,会生成对应的Mapper文件和SqlProvider文件

总结一下FluentMybatis和mybatis plus的区别

- Mybatis Plus Fluent Mybatis
代码生成 生成 Entity, Mapper, Wrapper等文件 只生成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语法渲染, 可读性更高

框架文档地址:https://gitee.com/fluent-mybatis/fluent-mybatis-docs

目录
相关文章
|
10月前
|
SQL XML IDE
Fluent Mybatis, 原生Mybatis, Mybatis Plus三者功能对比
使用fluent mybatis可以不用写具体的xml文件,通过java api可以构造出比较复杂的业务sql语句,做到代码逻辑和sql逻辑的合一。不再需要在Dao中组装查询或更新操作,在xml或mapper中再组装参数。那对比原生Mybatis, Mybatis Plus或者其他框架,FluentMybatis提供了哪些便利呢?
Fluent Mybatis, 原生Mybatis, Mybatis Plus三者功能对比
|
SQL XML JavaScript
Fluent Mybatis、原生Mybatis,、Mybatis Plus 大对比,哪个更好用?
Fluent Mybatis、原生Mybatis,、Mybatis Plus 大对比,哪个更好用?
|
SQL XML IDE
Fluent Mybatis 牛逼!做到代码逻辑和sql逻辑的合一
Fluent Mybatis 牛逼!做到代码逻辑和sql逻辑的合一
244 0
Fluent Mybatis 牛逼!做到代码逻辑和sql逻辑的合一
|
XML SQL IDE
干掉 XML Mapper,新出的 Fluent Mybatis 真香!
干掉 XML Mapper,新出的 Fluent Mybatis 真香!
455 0
干掉 XML Mapper,新出的 Fluent Mybatis 真香!
|
SQL XML IDE
Let's Fluent:更顺滑的MyBatis
只需瞅一眼Google Trends上全球Java界最热门的两款SQL映射框架近一年的对比数字,就不难了解其实力分布:在此领域,MyBatis早已占领东亚地区开发者市场,并以绝对优势稳居中国最抢手Java数据库访问框架之首。
Let's Fluent:更顺滑的MyBatis
|
11天前
|
SQL Java 数据库连接
挺详细的spring+springmvc+mybatis配置整合|含源代码
挺详细的spring+springmvc+mybatis配置整合|含源代码
109 1
|
9天前
|
算法 Java 数据库连接
Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档
Spring+MySQL+数据结构+集合,Alibaba珍藏版mybatis手写文档
|
1天前
|
Java 关系型数据库 数据库连接
MyBatis-Plus介绍及Spring Boot 3集成指南
MyBatis-Plus是一个MyBatis扩展工具,旨在简化Java开发中的CRUD操作。它具有无侵入性、低损耗、强大的CRUD功能、Lambda表达式支持、主键自动生成、ActiveRecord模式、全局操作和内置代码生成器等特点。在Spring Boot 3中集成MyBatis-Plus,需在pom.xml添加依赖,排除特定版本的mybatis-spring,并用@MapperScan注解指定Mapper接口路径。此外,还介绍了如何使用MyBatis-Plus代码生成器自动生成Mapper、Model、Service和Controller层代码,以加速开发。
34 2
MyBatis-Plus介绍及Spring Boot 3集成指南
|
2天前
|
Java 数据库连接 数据库
Spring整合Mybatis、Spring整合JUnit
Spring整合Mybatis、Spring整合JUnit
11 1
Spring整合Mybatis、Spring整合JUnit
|
3天前
|
Java 数据库连接 数据库
小唐开始学 Spring Boot——(3)利用mybatis访问数据表
小唐开始学 Spring Boot——(3)利用mybatis访问数据表