无需 XML Mapper,超级 Mybatis 代码即是 SQL 操作!真香?(一)

简介: 无需 XML Mapper,超级 Mybatis 代码即是 SQL 操作!真香?
  • Fluent Mybatis 介绍
  • Fluent Mybatis 特性一览
  • Fluent Mybatis 原理
  • Fluent Mybatis vs Mybatis vs Mybatis Plus
  • 实现需求比较
  • 生成代码编码比较
  • 三者对比总结

image.png

最近看到一个 ORM 框架 Fluent Mybatis 挺有意思的,整个设计理念非常符合工程师思维。

我对官方文档的部分内容进行了简单整理,通过这篇文章带你看看这个新晋 ORM 框架。

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

提前声明一下:对于这类个人维护和开发的框架,如果没有充分的了解,一定一定一定不要用在正式的项目上!不然后续遇到问题会很麻烦的!!!我目前对于 Fluent Mybatis 这个框架也仅仅是感兴趣,想要学习一下它的内部设计。

Fluent Mybatis 介绍

何为 Fluent Mybatis? Fluent Mybatis, 是一款 Mybatis 语法增强框架, 综合了 Mybatis Plus, Dynamic SQL, JPA 等框架特性和优点, 利用 annotation processor 生成代码。

Fluent Mybatis 有什么亮点? 使用 Fluent Mybatis 可以不用写具体的 XML 文件,通过 Java API 可以构造出比较复杂的业务 SQL 语句,做到代码逻辑和 SQL 逻辑的合一。不再需要在 Dao 中组装查询或更新操作,在 XML 或 Mapper 中再组装参数。

项目地址:https://gitee.com/fluent-mybatis/fluent-mybatis

系列文章:https://juejin.cn/column/7033388011911921678

image.png

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。

项目地址:https://github.com/YunaiV/ruoyi-vue-pro

Fluent Mybatis 特性一览

image.png

Fluent Mybatis 特性

基于微服务的思想,构建在 B2C 电商场景下的项目实战。核心技术栈,是 Spring Boot + Dubbo 。未来,会重构成 Spring Cloud Alibaba 。

项目地址:https://github.com/YunaiV/onemall

Fluent Mybatis 原理

image.png

Fluent Mybatis 原理

Fluent Mybatis vs Mybatis vs Mybatis Plus

对比原生 Mybatis, Mybatis Plus 或者其他框架,FluentMybatis 提供了哪些便利呢?

实现需求比较

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

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 max_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, 原生 Mybatis 和 Mybatis Plus 来实现一番。

使用 Fluent Mybatis 来实现上面的功能

image.png

代码地址:https://gitee.com/fluent-Mybatis/fluent-Mybatis-docs/tree/master/spring-boot-demo/

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

换成 Mybatis 原生实现上面的功能

1、定义 Mapper 接口

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

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

@Data
@Accessors(chain = true)
public class SummaryQuery {
    private Integer schoolTerm;
    private List<String> subjects;
    private Integer score;
    private Integer minCount;
}

3、定义实现业务逻辑的 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>

4、实现业务接口(这里是测试类, 实际应用中应该对应 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 会简单比较多,实现效果如下

image.png

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

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

其他框架,比如 TkMybatis 在封装和易用性上比 Mybatis Plus 要弱,就不再比较了。

生成代码编码比较

Fluent Mybatis 生成代码设置 :

public class AppEntityGenerator {
    static final String url = "jdbc:mysql://localhost:3306/fluent_Mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8";
    public static void main(String[] args) {
        FileGenerator.build(Abc.class);
    }
    @Tables(
        /** 数据库连接信息 **/
        url = url, username = "root", password = "password",
        /** Entity类parent package路径 **/
        basePack = "cn.org.fluent.Mybatis.springboot.demo",
        /** Entity代码源目录 **/
        srcDir = "spring-boot-demo/src/main/java",
        /** Dao代码源目录 **/
        daoDir = "spring-boot-demo/src/main/java",
        /** 如果表定义记录创建,记录修改,逻辑删除字段 **/
        gmtCreated = "gmt_create", gmtModified = "gmt_modified", logicDeleted = "is_deleted",
        /** 需要生成文件的表 ( 表名称:对应的Entity名称 ) **/
        tables = @Table(value = {"student_score"})
    )
    static class Abc {
    }
}

Mybatis Plus :

public class CodeGenerator {
    static String dbUrl = "jdbc:mysql://localhost:3306/fluent_Mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8";
    @Test
    public void generateCode() {
        GlobalConfig config = new GlobalConfig();
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setDbType(DbType.MYSQL)
            .setUrl(dbUrl)
            .setUsername("root")
            .setPassword("password")
            .setDriverName(Driver.class.getName());
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig
            .setCapitalMode(true)
            .setEntityLombokModel(false)
            .setNaming(NamingStrategy.underline_to_camel)
            .setColumnNaming(NamingStrategy.underline_to_camel)
            .setEntityTableFieldAnnotationEnable(true)
            .setFieldPrefix(new String[]{"test_"})
            .setInclude(new String[]{"student_score"})
            .setLogicDeleteFieldName("is_deleted")
            .setTableFillList(Arrays.asList(
                new TableFill("gmt_create", FieldFill.INSERT),
                new TableFill("gmt_modified", FieldFill.INSERT_UPDATE)));
        config
            .setActiveRecord(false)
            .setIdType(IdType.AUTO)
            .setOutputDir(System.getProperty("user.dir") + "/src/main/java/")
            .setFileOverride(true);
        new AutoGenerator().setGlobalConfig(config)
            .setDataSource(dataSourceConfig)
            .setStrategy(strategyConfig)
            .setPackageInfo(
                new PackageConfig()
                    .setParent("com.mp.demo")
                    .setController("controller")
                    .setEntity("entity")
            ).execute();
    }
}

三者对比总结

看完 3 个框架对同一个功能点的实现, 各位看官肯定会有自己的判断,笔者这里也总结了一份比较。

- Mybatis Plus Fluent Mybatis
代码生成 生成 Entity 生成 Entity, 再通过编译生成 Mapper, Query, UpdateSqlProvider
Generator 易用性
和 Mybatis 的共生关系 需替换原有的 SqlSessionFactoryBean 对 Mybatis 没有任何修改,原来怎么用还是怎么用
动态 SQL 构造方式 应用启动时, 根据 Entity 注解信息构造动态 xml 片段,注入到 Mybatis 解析器 应用编译时,根据 Entity 注解,编译生成对应方法的 SqlProvider,利用 Mybatis 的 Mapper@InsertProvider@SelectProvider@UpdateProvider 注解关联
动态 SQL 结果是否容易 DEBUG 跟踪 不容易 debug 容易,直接定位到 SQLProvider 方法上,设置断点即可
动态 SQL 构造 通过硬编码字段名称, 或者利用 Entityget 方法的 lambda 表达式 通过编译手段生成对应的方法名,直接调用方法即可
字段变更后的错误发现 通过 get 方法的 lambda 表达的可以编译发现,通过字段编码的无法编译发现 编译时便可发现
不同字段动态 SQL 构造方法 通过接口参数方式 通过接口名称方式, Fluent API 的编码效率更高
语法渲染特点 通过关键变量 select, update, set, and, or 可以利用 IDE 语法渲染, 可读性更高
相关文章
|
3月前
|
SQL XML Java
通过MyBatis的XML配置实现灵活的动态SQL查询
总结而言,通过MyBatis的XML配置实现灵活的动态SQL查询,可以让开发者以声明式的方式构建SQL语句,既保证了SQL操作的灵活性,又简化了代码的复杂度。这种方式可以显著提高数据库操作的效率和代码的可维护性。
258 18
|
8月前
|
SQL 自然语言处理 数据库
【Azure Developer】分享两段Python代码处理表格(CSV格式)数据 : 根据每列的内容生成SQL语句
本文介绍了使用Python Pandas处理数据收集任务中格式不统一的问题。针对两种情况:服务名对应多人拥有状态(1/0表示),以及服务名与人名重复列的情况,分别采用双层for循环和字典数据结构实现数据转换,最终生成Name对应的Services列表(逗号分隔)。此方法高效解决大量数据的人工处理难题,减少错误并提升效率。文中附带代码示例及执行结果截图,便于理解和实践。
218 4
|
8月前
|
SQL Java 数据库连接
【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号";"报错
【YashanDB知识库】解决mybatis的mapper文件sql语句结尾加分号";"报错
|
7月前
|
SQL Java 数据库连接
MyBatis动态SQL字符串空值判断,这个细节99%的程序员都踩过坑!
本文深入探讨了MyBatis动态SQL中字符串参数判空的常见问题。通过具体案例分析,对比了`name != null and name != &#39;&#39;`与`name != null and name != &#39; &#39;`两种写法的差异,指出后者可能引发逻辑混乱。为避免此类问题,建议在后端对参数进行预处理(如trim去空格),简化MyBatis判断逻辑,提升代码健壮性与可维护性。细节决定成败,严谨处理参数判空是写出高质量代码的关键。
955 0
|
8月前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
422 0
|
3月前
|
SQL Java 数据库连接
SSM相关问题-1--#{}和${}有什么区别吗?--Mybatis都有哪些动态sql?能简述一下动 态sql的执行原理吗?--Spring支持的几种bean的作用域 Scope
在MyBatis中,`#{}`是预处理占位符,可防止SQL注入,适用于大多数参数传递场景;而`${}`是直接字符串替换,不安全,仅用于动态表名、列名等特殊场景。二者在安全性、性能及使用场景上有显著区别。
78 0
|
5月前
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
933 1
Spring boot 使用mybatis generator 自动生成代码插件
|
6月前
|
SQL XML Java
菜鸟之路Day35一一Mybatis之XML映射与动态SQL
本文介绍了MyBatis框架中XML映射与动态SQL的使用方法,作者通过实例详细解析了XML映射文件的配置规范,包括namespace、id和resultType的设置。文章还对比了注解与XML映射的优缺点,强调复杂SQL更适合XML方式。在动态SQL部分,重点讲解了`&lt;if&gt;`、`&lt;where&gt;`、`&lt;set&gt;`、`&lt;foreach&gt;`等标签的应用场景,如条件查询、动态更新和批量删除,并通过代码示例展示了其灵活性与实用性。最后,通过`&lt;sql&gt;`和`&lt;include&gt;`实现代码复用,优化维护效率。
542 5
|
8月前
|
XML Java 数据库连接
二、搭建MyBatis采用xml方式,验证CRUD(增删改查操作)
二、搭建MyBatis采用xml方式,验证CRUD(增删改查操作)
258 21
|
8月前
|
SQL Java 数据库连接
【YashanDB 知识库】解决 mybatis 的 mapper 文件 sql 语句结尾加分号";"报错
【YashanDB 知识库】解决 mybatis 的 mapper 文件 sql 语句结尾加分号";"报错