再見 MybatisPlus,阿里推出新 ORM 框架更牛X
最近看到一個 ORM 框架 Fluent Mybatis 挺有意思的,整個設(shè)計(jì)理念非常符合工程師思維。
我對官方文檔的部分內(nèi)容進(jìn)行了簡單整理,通過這篇文章帶你看看這個新晉 ORM 框架。
官方文檔:https://gitee.com/fluent-mybatis/fluent-mybatis/wikis
提前聲明一下:對于這類個人維護(hù)和開發(fā)的框架,如果沒有充分的了解,一定一定一定不要用在正式的項(xiàng)目上!不然后續(xù)遇到問題會很麻煩的!!!我目前對于 Fluent Mybatis 這個框架也僅僅是感興趣,想要學(xué)習(xí)一下它的內(nèi)部設(shè)計(jì)。
Fluent Mybatis, 是一款 Mybatis 語法增強(qiáng)框架, 綜合了 Mybatis Plus, Dynamic SQL, JPA 等框架特性和優(yōu)點(diǎn), 利用 annotation processor 生成代碼。
Fluent Mybatis 有什么亮點(diǎn)?
使用 Fluent Mybatis 可以不用寫具體的 XML 文件,通過 Java API 可以構(gòu)造出比較復(fù)雜的業(yè)務(wù) SQL 語句,做到代碼邏輯和 SQL 邏輯的合一。不再需要在 Dao 中組裝查詢或更新操作,在 XML 或 Mapper 中再組裝參數(shù)。
項(xiàng)目地址:https://gitee.com/fluent-mybatis/fluent-mybatis
# Fluent Mybatis vs Mybatis vs Mybatis Plus
對比原生 Mybatis, Mybatis Plus 或者其他框架,F(xiàn)luentMybatis 提供了哪些便利呢?
我們通過一個比較典型的業(yè)務(wù)需求來具體實(shí)現(xiàn)和對比下,假如有學(xué)生成績表結(jié)構(gòu)如下:
現(xiàn)在有需求: 統(tǒng)計(jì) 2000 年三門學(xué)科('英語', '數(shù)學(xué)', '語文')及格分?jǐn)?shù)按學(xué)期,學(xué)科統(tǒng)計(jì)最低分,最高分和平均分, 且樣本數(shù)需要大于 1 條,統(tǒng)計(jì)結(jié)果按學(xué)期和學(xué)科排序
我們可以寫 SQL 語句如下:
使用 Fluent Mybatis 來實(shí)現(xiàn)上面的功能 :
我們可以看到 fluent api 的能力,以及 IDE 對代碼的渲染效果。
換成 Mybatis 原生實(shí)現(xiàn)上面的功能 :
1、定義 Mapper 接口
2、定義接口需要用到的參數(shù)實(shí)體 SummaryQuery
3、定義實(shí)現(xiàn)業(yè)務(wù)邏輯的 mapper xml 文件
4、實(shí)現(xiàn)業(yè)務(wù)接口(這里是測試類, 實(shí)際應(yīng)用中應(yīng)該對應(yīng) Dao 類)
換成 Mybatis Plus 實(shí)現(xiàn)上面的功能 :
Mybatis Plus 的實(shí)現(xiàn)比 Mybatis 會簡單比較多,實(shí)現(xiàn)效果如下
如紅框圈出的,寫 Mybatis Plus 實(shí)現(xiàn)用到了比較多字符串的硬編碼(可以用 Entity 的 get lambda 方法部分代替字符串編碼)。字符串的硬編碼,會給開發(fā)同學(xué)造成不小的使用門檻,個人覺的主要有 2 點(diǎn):
其他框架,比如 TkMybatis 在封裝和易用性上比 Mybatis Plus 要弱,就不再比較了。
Fluent Mybatis 生成代碼設(shè)置 :
Mybatis Plus :
接下來,我們來看看如何使用 Fluent Mybatis 來實(shí)現(xiàn)增刪改查。
執(zhí)行編譯。
IDE 編譯:
Maven 編譯:mvn clean compile Gradle 編譯:gradle clean compile
輸出:
現(xiàn)在,我們已經(jīng)通過一個簡單例子演示了 Fluent Mybatis 的強(qiáng)大功能, 在進(jìn)一步介紹 Fluent Mybatis 更強(qiáng)大功能前,我們揭示一下為啥我們只寫了一個數(shù)據(jù)表對應(yīng)的 Entity 類, 卻擁有了一系列增刪改查的數(shù)據(jù)庫操作方法。
Fluent Mybatis 根據(jù) Entity 類上 @FluentMybatis 注解在編譯時, 會在 target 目錄 class 目錄下自動編譯生成一系列文件:
沒錯,不是機(jī)器人 記得一定要等待,等待才有好東西
我對官方文檔的部分內(nèi)容進(jìn)行了簡單整理,通過這篇文章帶你看看這個新晉 ORM 框架。
官方文檔:https://gitee.com/fluent-mybatis/fluent-mybatis/wikis
提前聲明一下:對于這類個人維護(hù)和開發(fā)的框架,如果沒有充分的了解,一定一定一定不要用在正式的項(xiàng)目上!不然后續(xù)遇到問題會很麻煩的!!!我目前對于 Fluent Mybatis 這個框架也僅僅是感興趣,想要學(xué)習(xí)一下它的內(nèi)部設(shè)計(jì)。
# Fluent Mybatis 介紹
何為 Fluent Mybatis?
Fluent Mybatis, 是一款 Mybatis 語法增強(qiáng)框架, 綜合了 Mybatis Plus, Dynamic SQL, JPA 等框架特性和優(yōu)點(diǎn), 利用 annotation processor 生成代碼。
Fluent Mybatis 有什么亮點(diǎn)?
使用 Fluent Mybatis 可以不用寫具體的 XML 文件,通過 Java API 可以構(gòu)造出比較復(fù)雜的業(yè)務(wù) SQL 語句,做到代碼邏輯和 SQL 邏輯的合一。不再需要在 Dao 中組裝查詢或更新操作,在 XML 或 Mapper 中再組裝參數(shù)。
項(xiàng)目地址:https://gitee.com/fluent-mybatis/fluent-mybatis
# Fluent Mybatis 特性一覽
# Fluent Mybatis 原理
# Fluent Mybatis vs Mybatis vs Mybatis Plus
對比原生 Mybatis, Mybatis Plus 或者其他框架,F(xiàn)luentMybatis 提供了哪些便利呢?
一、實(shí)現(xiàn)需求比較
我們通過一個比較典型的業(yè)務(wù)需求來具體實(shí)現(xiàn)和對比下,假如有學(xué)生成績表結(jié)構(gòu)如下:
create table `student_score`(id bigint auto_increment comment '主鍵ID' primary key,student_id bigint not null comment '學(xué)號',gender_man tinyint default 0 not null comment '性別, 0:女; 1:男',school_term int null comment '學(xué)期',subject varchar(30) null comment '學(xué)科',score int null comment '成績',gmt_create datetime not null comment '記錄創(chuàng)建時間',gmt_modified datetime not null comment '記錄最后修改時間',is_deleted tinyint default 0 not null comment '邏輯刪除標(biāo)識') engine = InnoDB default charset=utf8;
現(xiàn)在有需求: 統(tǒng)計(jì) 2000 年三門學(xué)科('英語', '數(shù)學(xué)', '語文')及格分?jǐn)?shù)按學(xué)期,學(xué)科統(tǒng)計(jì)最低分,最高分和平均分, 且樣本數(shù)需要大于 1 條,統(tǒng)計(jì)結(jié)果按學(xué)期和學(xué)科排序
我們可以寫 SQL 語句如下:
那上面的需求,分別用 Fluent Mybatis, 原生 Mybatis 和 Mybatis Plus 來實(shí)現(xiàn)一番。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 >= 2000and subject in ('英語', '數(shù)學(xué)', '語文')and score >= 60and is_deleted = 0group by school_term, subjecthaving count(score) > 1order by school_term, subject;
使用 Fluent Mybatis 來實(shí)現(xiàn)上面的功能 :
我們可以看到 fluent api 的能力,以及 IDE 對代碼的渲染效果。
換成 Mybatis 原生實(shí)現(xiàn)上面的功能 :
1、定義 Mapper 接口
public interface MyStudentScoreMapper {List<Map<String, Object>> summaryScore(SummaryQuery paras);}
2、定義接口需要用到的參數(shù)實(shí)體 SummaryQuery
(chain = true)public class SummaryQuery {private Integer schoolTerm;
private List<String> subjects;
private Integer score;
private Integer minCount;}
3、定義實(shí)現(xiàn)業(yè)務(wù)邏輯的 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_scorefrom student_scorewhere school_term >=and subject in<foreach collection="subjects" item="item" open="(" close=")" separator=","></foreach>and score >=and is_deleted = 0group by school_term, subjecthaving count(score) > #{minCount}order by school_term, subject</select>
4、實(shí)現(xiàn)業(yè)務(wù)接口(這里是測試類, 實(shí)際應(yīng)用中應(yīng)該對應(yīng) Dao 類)
總之,直接使用 Mybatis,實(shí)現(xiàn)步驟還是相當(dāng)?shù)姆爆崳侍汀D菗Q成 Mybatis Plus 的效果怎樣呢?(SpringRunner.class)(classes = QuickStartApplication.class)public class MybatisDemo {private MyStudentScoreMapper mapper;
public void Mybatis_demo() {// 構(gòu)造查詢參數(shù)SummaryQuery paras = new SummaryQuery().setSchoolTerm(2000).setSubjects(Arrays.asList("英語", "數(shù)學(xué)", "語文")).setScore(60).setMinCount(1);
List<Map<String, Object>> summary = mapper.summaryScore(paras);System.out.println(summary);}}
換成 Mybatis Plus 實(shí)現(xiàn)上面的功能 :
Mybatis Plus 的實(shí)現(xiàn)比 Mybatis 會簡單比較多,實(shí)現(xiàn)效果如下
如紅框圈出的,寫 Mybatis Plus 實(shí)現(xiàn)用到了比較多字符串的硬編碼(可以用 Entity 的 get lambda 方法部分代替字符串編碼)。字符串的硬編碼,會給開發(fā)同學(xué)造成不小的使用門檻,個人覺的主要有 2 點(diǎn): - 字段名稱的記憶和敲碼困難
- Entity 屬性跟隨數(shù)據(jù)庫字段發(fā)生變更后的運(yùn)行時錯誤
其他框架,比如 TkMybatis 在封裝和易用性上比 Mybatis Plus 要弱,就不再比較了。
二、生成代碼編碼比較
Fluent Mybatis 生成代碼設(shè)置 :
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(/** 數(shù)據(jù)庫連接信息 **/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",/** 如果表定義記錄創(chuàng)建,記錄修改,邏輯刪除字段 **/gmtCreated = "gmt_create", gmtModified = "gmt_modified", logicDeleted = "is_deleted",/** 需要生成文件的表 ( 表名稱:對應(yīng)的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";
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();}}
三、三者對比總結(jié)
看完 3 個框架對同一個功能點(diǎn)的實(shí)現(xiàn), 各位看官肯定會有自己的判斷,筆者這里也總結(jié)了一份比較。
# Fluent Mybatis 實(shí)戰(zhàn)
接下來,我們來看看如何使用 Fluent Mybatis 來實(shí)現(xiàn)增刪改查。
引入依賴
新建 Maven 工程,設(shè)置項(xiàng)目編譯級別為 Java8 及以上,引入 Fluent Mybatis 依賴包。
<dependencies><!-- 引入fluent-mybatis 運(yùn)行依賴包, scope為compile --><dependency><groupId>com.github.atool</groupId><artifactId>fluent-mybatis</artifactId><version>1.9.3</version></dependency><!-- 引入fluent-mybatis-processor, scope設(shè)置為provider 編譯需要,運(yùn)行時不需要 --><dependency><groupId>com.github.atool</groupId><artifactId>fluent-mybatis-processor</artifactId><version>1.9.3</version></dependency></dependencies>
創(chuàng)建表
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 '創(chuàng)建時間',gmt_modified datetime DEFAULT NULL COMMENT '更新時間',is_deleted tinyint(2) DEFAULT 0 COMMENT '是否邏輯刪除') ENGINE = InnoDBCHARACTER SET = utf8 comment '簡單演示表';
# 創(chuàng)建數(shù)據(jù)庫表對應(yīng)的 Entity 類
創(chuàng)建數(shù)據(jù)庫表對應(yīng)的 Entity 類: HelloWorldEntity, 你只需要簡單的做 3 個動作:
- 根據(jù)駝峰命名規(guī)則命名 Entity 類和字段
- HelloWorldEntity 繼承 IEntity 接口類
- 在 HelloWorldEntity 類上加注解 @FluentMybatis
public 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 方法
public Class<? extends IEntity> entityClass() {return HelloWorldEntity.class;}}
執(zhí)行編譯。
IDE 編譯:
Maven 編譯:mvn clean compile Gradle 編譯:gradle clean compile
# 配置數(shù)據(jù)源
1.數(shù)據(jù)源 DataSource 配置
2.Mybatis 的 mapper 掃描路徑 3.Mybatis 的 SqlSessionFactoryBean很簡單吧,在這里,你即不需要配置任何 Mybatis xml 文件, 也不需要寫任何 · 接口, 但你已經(jīng)擁有了強(qiáng)大的增刪改查的功能,并且是 Fluent API,讓我們寫一個測試來見證一下 Fluent Mybatis 的魔法力量!(basePackages = "cn.org.atool.fluent.mybatis.demo1")("cn.org.atool.fluent.mybatis.demo1.entity.mapper")public class HelloWorldConfig {/*** 設(shè)置dataSource屬性** @return*/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*/public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);return bean;}
public MapperFactory mapperFactory() {return new MapperFactory();}}
# 測試
注入 HelloWorldEntity 對應(yīng)的 Mapper 類: HelloWorldMapper, 這個類是 Fluent Mybatis 編譯時生成的。
使用 HelloWorldMapper 進(jìn)行刪除、插入、查詢、修改操作。
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes = HelloWorldConfig.class)public class HelloWorldTest {/*** Fluent Mybatis編譯時生成的Mapper類*/@AutowiredHelloWorldMapper mapper;
@Testpublic void testHelloWorld() {/*** 為了演示方便,先刪除數(shù)據(jù)*/mapper.delete(mapper.query().where.id().eq(1L).end());/*** 插入數(shù)據(jù)*/HelloWorldEntity entity = new HelloWorldEntity();entity.setId(1L);entity.setSayHello("hello world");entity.setYourName("Fluent Mybatis");entity.setIsDeleted(false);mapper.insert(entity);/*** 查詢 id = 1 的數(shù)據(jù)*/HelloWorldEntity result1 = mapper.findOne(mapper.query().where.id().eq(1L).end());/*** 控制臺直接打印出查詢結(jié)果*/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 的數(shù)據(jù)*/HelloWorldEntity result2 = mapper.findOne(mapper.query().where.sayHello().like("hello").and.isDeleted().eq(false).end().limit(1));/*** 控制臺直接打印出查詢結(jié)果*/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}
神奇吧!我們再到數(shù)據(jù)庫中查看一下結(jié)果
現(xiàn)在,我們已經(jīng)通過一個簡單例子演示了 Fluent Mybatis 的強(qiáng)大功能, 在進(jìn)一步介紹 Fluent Mybatis 更強(qiáng)大功能前,我們揭示一下為啥我們只寫了一個數(shù)據(jù)表對應(yīng)的 Entity 類, 卻擁有了一系列增刪改查的數(shù)據(jù)庫操作方法。 Fluent Mybatis 根據(jù) Entity 類上 @FluentMybatis 注解在編譯時, 會在 target 目錄 class 目錄下自動編譯生成一系列文件:

- mapper/*Mapper : Mybatis 的 Mapper 定義接口, 定義了一系列通用的數(shù)據(jù)操作接口方法。
- dao/*BaseDao : Dao 實(shí)現(xiàn)基類, 所有的 DaoImpl 都繼承各自基類 根據(jù)分層編碼的原則,我們不會在 Service 類中直接使用 Mapper 類,而是引用 Dao 類。我們在 Dao 實(shí)現(xiàn)類中根據(jù)條件實(shí)現(xiàn)具體的數(shù)據(jù)操作方法。
- wrapper/*Query : Fluent Mybatis 核心類, 用來進(jìn)行動態(tài) sql 的構(gòu)造, 進(jìn)行條件查詢。
- wrapper/*Updater : Fluent Mybatis 核心類, 用來動態(tài)構(gòu)造 update 語句。
- helper/*Mapping : Entity 表字段和 Entity 屬性映射定義類
- helper/*Segment: Query 和 Updater 具體功能實(shí)現(xiàn), 包含幾個實(shí)現(xiàn): select, where, group by, having by, order by, limit
- IEntityRelation : 處理 Entity 關(guān)聯(lián)(一對一, 一對多, 多對多)關(guān)系的接口
- Ref : 引用 Fluent Mybatis 生成的對象的快捷入口工具類
# 總結(jié)
上面只是 Fluent Mybatis 常規(guī)實(shí)現(xiàn)增刪改查的方式,F(xiàn)luent Mybatis 現(xiàn)在又推出了專門面向表單級的增刪改查,聲明即實(shí)現(xiàn)。
官方說明:https://juejin.cn/post/7033388050012962852
加小編微信,回復(fù) 40 白嫖40套 java/spring/kafka/redis/netty 教程/代碼/視頻 等
掃二維碼,加我微信,回復(fù): 40
注意,不要亂回復(fù)沒錯,不是機(jī)器人 記得一定要等待,等待才有好東西
評論
圖片
表情

