再见 MybatisPlus,阿里推出新 ORM 框架更牛X

最近看到一个 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

图片

 

# Fluent Mybatis 特性一览

图片

# 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_scorefrom student_scorewhere school_term >= 2000  and subject in ('英语', '数学', '语文')  and score >= 60  and is_deleted = 0group by school_term, subjecthaving count(score) > 1order by school_term, subject;

那上面的需求,分别用 Fluent Mybatis, 原生 Mybatis 和 Mybatis Plus 来实现一番。

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

图片

我们可以看到 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 会简单比较多,实现效果如下

图片

如红框圈出的,写 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 个框架对同一个功能点的实现, 各位看官肯定会有自己的判断,笔者这里也总结了一份比较。

图片

# Fluent Mybatis 实战

接下来,我们来看看如何使用 Fluent Mybatis 来实现增删改查。

引入依赖

新建 Maven 工程,设置项目编译级别为 Java8 及以上,引入 Fluent Mybatis 依赖包。

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

创建表

create schema fluent_mybatis;
create table hello_world(    id           bigint unsigned auto_increment primary key,    say_hello    varchar(100) null,    your_name    varchar(100) null,    gmt_created   datetime   DEFAULT NULL COMMENT '创建时间',    gmt_modified datetime   DEFAULT NULL COMMENT '更新时间',    is_deleted   tinyint(2) DEFAULT 0 COMMENT '是否逻辑删除') ENGINE = InnoDB  CHARACTER SET = utf8 comment '简单演示表';

# 创建数据库表对应的 Entity 类

创建数据库表对应的 Entity 类: HelloWorldEntity, 你只需要简单的做 3 个动作:

  1. 根据驼峰命名规则命名 Entity 类和字段

  2. HelloWorldEntity 继承 IEntity 接口类

  3. 在 HelloWorldEntity 类上加注解 @FluentMybatis

@FluentMybatispublic class HelloWorldEntity extends RichEntity {    private Long id;
    private String sayHello;
    private String yourName;
    private Date gmtCreated;
    private Date gmtModified;
    private Boolean isDeleted;
    // get, set, toString 方法
   @Override   public Class<? extends IEntity> entityClass() {      return HelloWorldEntity.class;   }}

执行编译。

IDE 编译:

图片

Maven 编译:mvn clean compile

Gradle 编译:gradle clean compile

# 配置数据源

1.数据源 DataSource 配置

2.Mybatis 的 mapper 扫描路径

3.Mybatis 的 SqlSessionFactoryBean

@ComponentScan(basePackages = "cn.org.atool.fluent.mybatis.demo1")@MapperScan("cn.org.atool.fluent.mybatis.demo1.entity.mapper")@Configurationpublic class HelloWorldConfig {    /**     * 设置dataSource属性     *     * @return     */    @Bean    public DataSource dataSource() {        BasicDataSource dataSource = new BasicDataSource();        dataSource.setDriverClassName("com.mysql.jdbc.Driver");        dataSource.setUrl("jdbc:mysql://localhost:3306/fluent_mybatis?useUnicode=true&characterEncoding=utf8");        dataSource.setUsername("root");        dataSource.setPassword("password");        return dataSource;    }
    /**     * 定义mybatis的SqlSessionFactoryBean     *     * @param dataSource     * @return     */    @Bean    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();        bean.setDataSource(dataSource);        return bean;    }
   @Bean   public MapperFactory mapperFactory() {      return new MapperFactory();   }}

很简单吧,在这里,你即不需要配置任何 Mybatis xml 文件, 也不需要写任何 · 接口, 但你已经拥有了强大的增删改查的功能,并且是 Fluent API,让我们写一个测试来见证一下 Fluent Mybatis 的魔法力量!

# 测试

注入 HelloWorldEntity 对应的 Mapper 类: HelloWorldMapper, 这个类是 Fluent Mybatis 编译时生成的。

使用 HelloWorldMapper 进行删除、插入、查询、修改操作。

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = HelloWorldConfig.class)public class HelloWorldTest {    /**     * Fluent Mybatis编译时生成的Mapper类     */    @Autowired    HelloWorldMapper mapper;
    @Test    public void testHelloWorld() {        /**         * 为了演示方便,先删除数据         */        mapper.delete(mapper.query()            .where.id().eq(1L).end());        /**         * 插入数据         */        HelloWorldEntity entity = new HelloWorldEntity();        entity.setId(1L);        entity.setSayHello("hello world");        entity.setYourName("Fluent Mybatis");        entity.setIsDeleted(false);        mapper.insert(entity);        /**         * 查询 id = 1 的数据         */        HelloWorldEntity result1 = mapper.findOne(mapper.query()            .where.id().eq(1L).end());        /**         * 控制台直接打印出查询结果         */        System.out.println("1. HelloWorldEntity:" + result1.toString());        /**         * 更新id = 1的记录         */        mapper.updateBy(mapper.updater()            .set.sayHello().is("say hello, say hello!")            .set.yourName().is("Fluent Mybatis is powerful!").end()            .where.id().eq(1L).end()        );        /**         * 查询 id = 1 的数据         */        HelloWorldEntity result2 = mapper.findOne(mapper.query()            .where.sayHello().like("hello")            .and.isDeleted().eq(false).end()            .limit(1)        );        /**         * 控制台直接打印出查询结果         */        System.out.println("2. HelloWorldEntity:" + result2.toString());    }}

输出:

 
 HelloWorldEntity:HelloWorldEntity{id=1, sayHello='hello world', yourName='Fluent Mybatis', gmtCreate=null, gmtModified=null, isDeleted=false} HelloWorldEntity:HelloWorldEntity{id=1, sayHello='say hello, say hello!', yourName='Fluent Mybatis is powerful!', gmtCreate=null, gmtModified=null, isDeleted=false}

神奇吧!我们再到数据库中查看一下结果

图片

现在,我们已经通过一个简单例子演示了 Fluent Mybatis 的强大功能, 在进一步介绍 Fluent Mybatis 更强大功能前,我们揭示一下为啥我们只写了一个数据表对应的 Entity 类, 却拥有了一系列增删改查的数据库操作方法。

Fluent Mybatis 根据 Entity 类上 @FluentMybatis 注解在编译时, 会在 target 目录 class 目录下自动编译生成一系列文件:

图片

这些文件的具体作用如下:

  • mapper/*Mapper : Mybatis 的 Mapper 定义接口, 定义了一系列通用的数据操作接口方法。

  • dao/*BaseDao : Dao 实现基类, 所有的 DaoImpl 都继承各自基类 根据分层编码的原则,我们不会在 Service 类中直接使用 Mapper 类,而是引用 Dao 类。我们在 Dao 实现类中根据条件实现具体的数据操作方法。

  • wrapper/*Query : Fluent Mybatis 核心类, 用来进行动态 sql 的构造, 进行条件查询。

  • wrapper/*Updater : Fluent Mybatis 核心类, 用来动态构造 update 语句。

  • helper/*Mapping : Entity 表字段和 Entity 属性映射定义类

  • helper/*Segment: Query 和 Updater 具体功能实现, 包含几个实现: select, where, group by, having by, order by, limit

  • IEntityRelation : 处理 Entity 关联(一对一, 一对多, 多对多)关系的接口

  • Ref : 引用 Fluent Mybatis 生成的对象的快捷入口工具类

# 总结

上面只是 Fluent Mybatis 常规实现增删改查的方式,Fluent Mybatis 现在又推出了专门面向表单级的增删改查,声明即实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/303145.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Golang | Leetcode Golang题解之第19题删除链表的倒数第N个结点

题目&#xff1a; 题解&#xff1a; func removeNthFromEnd(head *ListNode, n int) *ListNode {dummy : &ListNode{0, head}first, second : head, dummyfor i : 0; i < n; i {first first.Next}for ; first ! nil; first first.Next {second second.Next}second.N…

Redis缓存设计

文章目录 1 缓存的收益与成本分析1.1 收益1.2 成本 2 缓存更新策略的选择和使用场景2.1 LRU/LFU/FIFO算法剔除2.2 超时剔除2.3 主动更新2.4 缓存更新策略对比 2.5 最佳实践 3 缓存粒度控制方法3.1 缓存全部数据3.2 缓存部分数据3.3 缓存粒度控制方法对比 4 缓存穿透问题优化4.1…

(2022级)成都工业学院软件构造实验三:面向数据的软件构造

写在前面 1、基于2022级软件工程实验指导书 2、代码仅提供参考 3、如果代码不满足你的要求&#xff0c;请寻求其他的途径 运行环境 window11家庭版 IntelliJ IDEA 2023.2.2 jdk17.0.6 实验要求 任务&#xff1a; ‍一、构造任务4&#xff1a;批量产生习题并用文件存储…

IntelliJ IDEA 2024.1安装与激活[破解]

一&#xff1a;IDEA官方下载 ①如题&#xff0c;先到IDEA官方下载&#xff0c;简简单单 ②IDEA官方&#xff1a;IntelliJ IDEA – the Leading Java and Kotlin IDE 二&#xff1a;获取脚本 &#x1f31f;网盘下载&#xff1a;jetbra (密码&#xff1a;lzh7) &#x1f31f;获取…

STC89C52学习笔记(七)

STC89C52学习笔记&#xff08;七&#xff09; 综述&#xff1a;本文介绍了串口以及讲述了串口相关寄存器如何配置并给予相关代码。 一、修改代码注意事项 在修改代码时不要一次性加入一堆代码&#xff0c;不利于定位错误。可以先注释一些代码&#xff0c;待解决完毕问题后再…

物联网农业四情在线监测系统

TH-Q2随着科技的飞速发展和信息化时代的来临&#xff0c;物联网技术在各个领域都取得了显著的应用成果。其中&#xff0c;物联网农业四情在线监测系统作为农业现代化的重要组成部分&#xff0c;正在为农业生产带来革命性的变革。 一、物联网农业四情在线监测系统的概念 物联网…

大模型笔记:Prompt tuning

1 NLP模型的几个阶段 1.1 第一阶段&#xff08;在深度学习出现之前&#xff09; 通常聚焦于特征工程&#xff08;feature engineering&#xff09;利用领域知识从数据中提取好的特征 1.2 第二阶段&#xff08;在深度学习出现之后&#xff09; 特征可以从数据中习得——>…

使用 kaggle api 实现 kaggle 数据快速下载

在下载kaggle数据集时&#xff0c;以猫狗数据集举例子&#xff0c;有两种方法&#xff1a; Dogs vs. Cats | Kaggle 1&#xff1a;直接浏览器下载&#xff0c;较慢&#xff0c;不推荐。 2&#xff1a;使用kaggle API下载&#xff0c;很快。本文重点介绍。详情可以&#xff1…

Web前端-Ajax

Ajax 概念:Asynchronous JavaScript And XML,异步的JavaScript和XML。 作用: 1.数据交换:通过Ajax可以给服务器发送请求,并获取服务器响应的数据。 2.异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用的校验等等…

ARM嵌入式控制器带HDMI为制造业注入智能动力

工业自动化技术的飞速发展&#xff0c;IT与OT的融合已成为推动工业进步的关键力量。在这个背景下&#xff0c;ARM工业计算机凭借其强大的功能和灵活性&#xff0c;成为了边缘自动化领域的一颗新星。今天&#xff0c;我们将深入探讨这款设备如何通过其独特的特性&#xff0c;助力…

Scrapy 爬取m3u8视频

Scrapy 爬取m3u8视频 【一】效果展示 爬取ts文件样式 合成的MP4文件 【二】分析m3u8文件路径 视频地址&#xff1a;[在线播放我独自升级 第03集 - 高清资源](https://www.physkan.com/ph/175552-8-3.html) 【1】找到m3u8文件 这里任务目标很明确 就是找m3u8文件 打开浏览器…

【C语言】“vid”Microsoft Visual Studio安装及应用(检验内存泄露)

文章目录 前言安装包获取配置VLD完成 前言 我们在写代码时往往容易存在内存泄漏的情况&#xff0c;所以存在这样一个名为VLD的工具用来检验内存泄漏&#xff0c;现在我来教大家安装一下 安装包获取 vld下载网址&#xff1a;https://github.com/KindDragon/vld/releases/tag/…

三支冲突分析介绍

Pawlak最早通过观察一组智能体对一组问题的意见&#xff0c;提出了冲突分析模型。U表示对象集&#xff0c;V表示属性集&#xff0c;R表示对象集和属性集之间的二元关系&#xff0c;这样一个刻画冲突分析的信息系统通过三元组&#xff08;U&#xff0c;V&#xff0c;R&#xff0…

物理服务器与云服务器的租用对比

​ 物理服务器&#xff1a;每个基于 Web 的应用程序都依赖于一个服务器&#xff0c;该服务器提供网络中的数据存储&#xff0c;并可根据请求提供给客户端。例如&#xff0c;用户使用浏览器访问 Web 应用程序。服务器可确保托管客户端可以使用该硬件组件。与其他托管可能性相比&…

LeetCode 2529. 正整数和负整数的最大计数——每日一题

上一篇博客&#xff1a;LeetCode 993. 二叉树的堂兄弟节点——每日一题 写在前面&#xff1a;大家好&#xff01;我是晴空๓。如果博客中有不足或者的错误的地方欢迎在评论区或者私信我指正&#xff0c;感谢大家的不吝赐教。我的唯一博客更新地址是&#xff1a;https://ac-fun.…

【黑马头条】-day07APP端文章搜索-ES-mongoDB

文章目录 今日内容1 搭建es环境1.1 拉取es镜像1.2 创建容器1.3 配置中文分词器ik1.4 测试 2 app文章搜索2.1 需求说明2.2 思路分析2.3 创建索引和映射2.3.1 PUT请求添加映射2.3.2 其他操作 2.4 初始化索引库数据2.4.1 导入es-init2.4.2 es-init配置2.4.3 导入数据2.4.4 查询已导…

Elastisearch、Kibana安装

Elastisearch简介 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch &#xff08;以下简称 Elastic&#xff09;是目前全文搜索引擎的首选。它可以快速地储存、搜索和分析海量数据。 Elastic 的底层是开源库 Lucene。但是&#xff0c;你没法直接用 Lucene&#xff0…

[网鼎杯 2020 玄武组]SSRFMe

[网鼎杯 2020 玄武组]SSRFMe 源码 <?php function check_inner_ip($url) {$match_resultpreg_match(/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/,$url);if (!$match_result){die(url fomat error);}try{$url_parseparse_url($url);}catch(Exception $e){die(url foma…

真实世界的映照-DDD实体

什么是实体&#xff1f; 实体&#xff0c;官方的解释是&#xff1a;实体&#xff08;Entity&#xff0c;又称为Reference Object&#xff09;很多对象不是通过他们的属性定义的&#xff0c;而是通过一连串的连续事件和标识定义的。主要由标识定义的对象被称为ENTITY。 但&…

RTThread studio 驱动开发

rtthread 驱动使用的两种情况 rtthread studio 自动生成 由 RT Thread Studio 自动生成&#xff0c;无需修改任何文件或者简单定义几个宏即可直接使用的驱动&#xff0c;如 GPIO&#xff0c;UART&#xff0c;I2C&#xff0c;SPI&#xff0c;SDIO 和 ETH 等。 使用 RT-Thread S…