<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          無需 XML Mapper,超級 Mybatis 代碼即是 SQL 操作!真香?

          共 7815字,需瀏覽 16分鐘

           ·

          2022-03-04 12:19


          來源:JavaGuide

          • Fluent Mybatis 介紹
          • Fluent Mybatis 特性一覽
          • Fluent Mybatis 原理
          • Fluent Mybatis vs Mybatis vs Mybatis Plus
            • 實現(xiàn)需求比較
            • 生成代碼編碼比較
            • 三者對比總結(jié)
          • Fluent Mybatis 實戰(zhàn)
            • 引入依賴
            • 創(chuàng)建表
            • 創(chuàng)建數(shù)據(jù)庫表對應(yīng)的 Entity 類
            • 配置數(shù)據(jù)源
            • 測試
            • 總結(jié)

          最近看到一個 ORM 框架 Fluent Mybatis 挺有意思的,整個設(shè)計理念非常符合工程師思維。

          我對官方文檔的部分內(nèi)容進行了簡單整理,通過這篇文章帶你看看這個新晉 ORM 框架。

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

          提前聲明一下:對于這類個人維護和開發(fā)的框架,如果大家沒有充分的了解,一定一定一定不要用在正式的項目上!不然后續(xù)遇到問題會很麻煩的!!!我目前對于 Fluent Mybatis 這個框架也僅僅是感興趣,想要學(xué)習(xí)一下它的內(nèi)部設(shè)計。

          Fluent Mybatis 介紹

          何為 Fluent Mybatis? Fluent Mybatis, 是一款 Mybatis 語法增強框架, 綜合了 Mybatis Plus, Dynamic SQL, JPA 等框架特性和優(yōu)點, 利用 annotation processor 生成代碼。

          Fluent Mybatis 有什么亮點? 使用 Fluent Mybatis 可以不用寫具體的 XML 文件,通過 Java API 可以構(gòu)造出比較復(fù)雜的業(yè)務(wù) SQL 語句,做到代碼邏輯和 SQL 邏輯的合一。不再需要在 Dao 中組裝查詢或更新操作,在 XML 或 Mapper 中再組裝參數(shù)。

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

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

          img

          Fluent Mybatis 特性一覽

          img

          Fluent Mybatis 原理

          img

          Fluent Mybatis vs Mybatis vs Mybatis Plus

          對比原生 Mybatis, Mybatis Plus 或者其他框架,F(xiàn)luentMybatis 提供了哪些便利呢?

          實現(xiàn)需求比較

          我們通過一個比較典型的業(yè)務(wù)需求來具體實現(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)計 2000 年三門學(xué)科('英語', '數(shù)學(xué)', '語文')及格分?jǐn)?shù)按學(xué)期,學(xué)科統(tǒng)計最低分,最高分和平均分, 且樣本數(shù)需要大于 1 條,統(tǒng)計結(jié)果按學(xué)期和學(xué)科排序

          我們可以寫 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?('英語',?'數(shù)學(xué)',?'語文')
          ??and?score?>=?60
          ??and?is_deleted?=?0
          group?by?school_term,?subject
          having?count(score)?>?1
          order?by?school_term,?subject;
          復(fù)制代碼

          那上面的需求,分別用 Fluent Mybatis, 原生 Mybatis 和 Mybatis Plus 來實現(xiàn)一番。

          使用 Fluent Mybatis 來實現(xiàn)上面的功能

          img

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

          我們可以看到 fluent api 的能力,以及 IDE 對代碼的渲染效果。

          換成 Mybatis 原生實現(xiàn)上面的功能

          1、定義 Mapper 接口

          public?interface?MyStudentScoreMapper?{
          ????List>?summaryScore(SummaryQuery?paras);
          }

          2、定義接口需要用到的參數(shù)實體 SummaryQuery

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

          ????private?List?subjects;

          ????private?Integer?score;

          ????private?Integer?minCount;
          }
          復(fù)制代碼

          3、定義實現(xiàn)業(yè)務(wù)邏輯的 mapper xml 文件

          "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
          ????"subjects"?item="item"?open="("?close=")"?separator=",">
          ????????#{item}
          ????
          ????and?score?>=?#{score}
          ????and?is_deleted?=?0
          ????group?by?school_term,?subject
          ????having?count(score)?>?#
          {minCount}
          ????order?by?school_term,?subject

          復(fù)制代碼

          4、實現(xiàn)業(yè)務(wù)接口(這里是測試類, 實際應(yīng)用中應(yīng)該對應(yīng) Dao 類)

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

          ????@Test
          ????public?void?Mybatis_demo()?{
          ????????//?構(gòu)造查詢參數(shù)
          ????????SummaryQuery?paras?=?new?SummaryQuery()
          ????????????.setSchoolTerm(2000)
          ????????????.setSubjects(Arrays.asList("英語",?"數(shù)學(xué)",?"語文"))
          ????????????.setScore(60)
          ????????????.setMinCount(1);

          ????????List>?summary?=?mapper.summaryScore(paras);
          ????????System.out.println(summary);
          ????}
          }
          復(fù)制代碼

          總之,直接使用 Mybatis,實現(xiàn)步驟還是相當(dāng)?shù)姆爆崳侍汀D菗Q成 Mybatis Plus 的效果怎樣呢?

          換成 Mybatis Plus 實現(xiàn)上面的功能 :

          Mybatis Plus 的實現(xiàn)比 Mybatis 會簡單比較多,實現(xiàn)效果如下

          img

          如紅框圈出的,寫 Mybatis Plus 實現(xiàn)用到了比較多字符串的硬編碼(可以用 Entity 的 get lambda 方法部分代替字符串編碼)。字符串的硬編碼,會給開發(fā)同學(xué)造成不小的使用門檻,個人覺的主要有 2 點:

          1. 字段名稱的記憶和敲碼困難
          2. Entity 屬性跟隨數(shù)據(jù)庫字段發(fā)生變更后的運行時錯誤

          其他框架,比如 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";

          ????@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();
          ????}
          }

          三者對比總結(jié)

          看完 3 個框架對同一個功能點的實現(xiàn), 各位看官肯定會有自己的判斷,筆者這里也總結(jié)了一份比較。

          Fluent Mybatis 實戰(zhàn)

          接下來,我們來看看如何使用 Fluent Mybatis 來實現(xiàn)增刪改查。

          引入依賴

          新建 Maven 工程,設(shè)置項目編譯級別為 Java8 及以上,引入 Fluent Mybatis 依賴包。




          com.github.atool
          fluent-mybatis
          1.9.3



          com.github.atool
          fluent-mybatis-processor
          1.9.3


          創(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 = InnoDB
          CHARACTER SET = utf8 comment '簡單演示表';

          創(chuàng)建數(shù)據(jù)庫表對應(yīng)的 Entity 類

          創(chuàng)建數(shù)據(jù)庫表對應(yīng)的 Entity 類: HelloWorldEntity, 你只需要簡單的做 3 個動作:

          1. 根據(jù)駝峰命名規(guī)則命名 Entity 類和字段
          2. HelloWorldEntity 繼承 IEntity 接口類
          3. HelloWorldEntity 類上加注解 @FluentMybatis
          @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 方法

          @Override
          public Class entityClass() {
          return HelloWorldEntity.class;
          }
          }

          執(zhí)行編譯。

          IDE 編譯:

          img

          Maven 編譯:mvn clean compile

          Gradle 編譯:gradle clean compile

          配置數(shù)據(jù)源

          1. 數(shù)據(jù)源 DataSource 配置
          2. Mybatis 的 mapper 掃描路徑
          3. Mybatis 的 SqlSessionFactoryBean
          @ComponentScan(basePackages?=?"cn.org.atool.fluent.mybatis.demo1")
          @MapperScan("cn.org.atool.fluent.mybatis.demo1.entity.mapper")
          @Configuration
          public?class?HelloWorldConfig?{
          ????/**
          ?????*?設(shè)置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 文件, 也不需要寫任何 · 接口, 但你已經(jīng)擁有了強大的增刪改查的功能,并且是 Fluent API,讓我們寫一個測試來見證一下 Fluent Mybatis 的魔法力量!

          測試

          注入 HelloWorldEntity 對應(yīng)的 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()?{
          ????????/**
          ?????????*?為了演示方便,先刪除數(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());
          ????}
          }

          輸出:

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

          神奇吧!我們再到數(shù)據(jù)庫中查看一下結(jié)果

          img

          現(xiàn)在,我們已經(jīng)通過一個簡單例子演示了 Fluent Mybatis 的強大功能, 在進一步介紹 Fluent Mybatis 更強大功能前,我們揭示一下為啥我們只寫了一個數(shù)據(jù)表對應(yīng)的 Entity 類, 卻擁有了一系列增刪改查的數(shù)據(jù)庫操作方法。

          Fluent Mybatis 根據(jù) Entity 類上 @FluentMybatis 注解在編譯時, 會在 target 目錄 class 目錄下自動編譯生成一系列文件:

          img

          這些文件的具體作用如下:

          • mapper/*Mapper : Mybatis 的 Mapper 定義接口, 定義了一系列通用的數(shù)據(jù)操作接口方法。
          • dao/*BaseDao : Dao 實現(xiàn)基類, 所有的 DaoImpl 都繼承各自基類 根據(jù)分層編碼的原則,我們不會在 Service 類中直接使用 Mapper 類,而是引用 Dao 類。我們在 Dao 實現(xiàn)類中根據(jù)條件實現(xiàn)具體的數(shù)據(jù)操作方法。
          • wrapper/*Query : Fluent Mybatis 核心類, 用來進行動態(tài) sql 的構(gòu)造, 進行條件查詢。
          • wrapper/*Updater : Fluent Mybatis 核心類, 用來動態(tài)構(gòu)造 update 語句。
          • helper/*Mapping : Entity 表字段和 Entity 屬性映射定義類
          • helper/*Segment: QueryUpdater 具體功能實現(xiàn), 包含幾個實現(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ī)實現(xiàn)增刪改查的方式,F(xiàn)luent Mybatis 現(xiàn)在又推出了專門面向表單級的增刪改查,聲明即實現(xiàn)。官方說明:https://juejin.cn/post/7033388050012962852 。

          瀏覽 48
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人三区 | 97久久爽无码人妻AⅤ精品牛牛 | 天堂中文视频在线 | 欧美 中文 日韩 | 丁香五月综合 |