<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>

          超級(jí) Mybatis! 代碼即是 SQL 操作,真香?

          共 7815字,需瀏覽 16分鐘

           ·

          2022-03-03 15:08


          來(lái)源:JavaGuide

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

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

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

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

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

          Fluent Mybatis 介紹

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

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

          項(xiàng)目地址: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

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

          實(shí)現(xiàn)需求比較

          我們通過(guò)一個(gè)比較典型的業(yè)務(wù)需求來(lái)具體實(shí)現(xiàn)和對(duì)比下,假如有學(xué)生成績(jī)表結(jié)構(gòu)如下:

          create?table?`student_score`
          (
          ????id???????????bigint?auto_increment?comment?'主鍵ID'?primary?key,
          ????student_id???bigint????????????not?null?comment?'學(xué)號(hào)',
          ????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?'成績(jī)',
          ????gmt_create???datetime??????????not?null?comment?'記錄創(chuàng)建時(shí)間',
          ????gmt_modified?datetime??????????not?null?comment?'記錄最后修改時(shí)間',
          ????is_deleted???tinyint?default?0?not?null?comment?'邏輯刪除標(biāo)識(shí)'
          )?engine?=?InnoDB?default?charset=utf8;

          現(xiàn)在有需求: 統(tǒng)計(jì) 2000 年三門學(xué)科('英語(yǔ)', '數(shù)學(xué)', '語(yǔ)文')及格分?jǐn)?shù)按學(xué)期,學(xué)科統(tǒng)計(jì)最低分,最高分和平均分, 且樣本數(shù)需要大于 1 條,統(tǒng)計(jì)結(jié)果按學(xué)期和學(xué)科排序

          我們可以寫 SQL 語(yǔ)句如下:

          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?('英語(yǔ)',?'數(shù)學(xué)',?'語(yǔ)文')
          ??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 來(lái)實(shí)現(xiàn)一番。

          使用 Fluent Mybatis 來(lái)實(shí)現(xiàn)上面的功能

          img

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

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

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

          1、定義 Mapper 接口

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

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

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

          ????private?List?subjects;

          ????private?Integer?score;

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

          3、定義實(shí)現(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、實(shí)現(xiàn)業(yè)務(wù)接口(這里是測(cè)試類, 實(shí)際應(yīng)用中應(yīng)該對(duì)應(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("英語(yǔ)",?"數(shù)學(xué)",?"語(yǔ)文"))
          ????????????.setScore(60)
          ????????????.setMinCount(1);

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

          總之,直接使用 Mybatis,實(shí)現(xiàn)步驟還是相當(dāng)?shù)姆爆?,效率太低。那換成 Mybatis Plus 的效果怎樣呢?

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

          Mybatis Plus 的實(shí)現(xiàn)比 Mybatis 會(huì)簡(jiǎn)單比較多,實(shí)現(xiàn)效果如下

          img

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

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

          其他框架,比如 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ù)庫(kù)連接信息?**/
          ????????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",
          ????????/**?需要生成文件的表?(?表名稱:對(duì)應(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();
          ????}
          }

          三者對(duì)比總結(jié)

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

          Fluent Mybatis 實(shí)戰(zhàn)

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

          引入依賴

          新建 Maven 工程,設(shè)置項(xiàng)目編譯級(jí)別為 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)建時(shí)間',
          gmt_modified datetime DEFAULT NULL COMMENT '更新時(shí)間',
          is_deleted tinyint(2) DEFAULT 0 COMMENT '是否邏輯刪除'
          ) ENGINE = InnoDB
          CHARACTER SET = utf8 comment '簡(jiǎn)單演示表';

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

          創(chuàng)建數(shù)據(jù)庫(kù)表對(duì)應(yīng)的 Entity 類: HelloWorldEntity, 你只需要簡(jiǎn)單的做 3 個(gè)動(dòng)作:

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

          很簡(jiǎn)單吧,在這里,你即不需要配置任何 Mybatis xml 文件, 也不需要寫任何 · 接口, 但你已經(jīng)擁有了強(qiáng)大的增刪改查的功能,并且是 Fluent API,讓我們寫一個(gè)測(cè)試來(lái)見(jiàn)證一下 Fluent Mybatis 的魔法力量!

          測(cè)試

          注入 HelloWorldEntity 對(duì)應(yīng)的 Mapper 類: HelloWorldMapper, 這個(gè)類是 Fluent Mybatis 編譯時(shí)生成的。

          使用 HelloWorldMapper 進(jìn)行刪除、插入、查詢、修改操作。

          @RunWith(SpringJUnit4ClassRunner.class)
          @ContextConfiguration(classes?
          =?HelloWorldConfig.class)
          public?class?HelloWorldTest?
          {
          ????/**
          ?????*?Fluent?Mybatis編譯時(shí)生成的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());
          ????????/**
          ?????????*?控制臺(tái)直接打印出查詢結(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)
          ????????);
          ????????/**
          ?????????*?控制臺(tái)直接打印出查詢結(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}

          神奇吧!我們?cè)俚綌?shù)據(jù)庫(kù)中查看一下結(jié)果

          img

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

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

          img

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

          • mapper/*Mapper : Mybatis 的 Mapper 定義接口, 定義了一系列通用的數(shù)據(jù)操作接口方法。
          • dao/*BaseDao : Dao 實(shí)現(xiàn)基類, 所有的 DaoImpl 都繼承各自基類 根據(jù)分層編碼的原則,我們不會(huì)在 Service 類中直接使用 Mapper 類,而是引用 Dao 類。我們?cè)?Dao 實(shí)現(xiàn)類中根據(jù)條件實(shí)現(xiàn)具體的數(shù)據(jù)操作方法。
          • wrapper/*Query : Fluent Mybatis 核心類, 用來(lái)進(jìn)行動(dòng)態(tài) sql 的構(gòu)造, 進(jìn)行條件查詢。
          • wrapper/*Updater : Fluent Mybatis 核心類, 用來(lái)動(dòng)態(tài)構(gòu)造 update 語(yǔ)句。
          • helper/*Mapping : Entity 表字段和 Entity 屬性映射定義類
          • helper/*Segment: QueryUpdater 具體功能實(shí)現(xiàn), 包含幾個(gè)實(shí)現(xiàn): select, where, group by, having by, order by, limit
          • IEntityRelation : 處理 Entity 關(guān)聯(lián)(一對(duì)一, 一對(duì)多, 多對(duì)多)關(guān)系的接口
          • Ref : 引用 Fluent Mybatis 生成的對(duì)象的快捷入口工具類

          總結(jié)

          上面只是 Fluent Mybatis 常規(guī)實(shí)現(xiàn)增刪改查的方式,F(xiàn)luent Mybatis 現(xiàn)在又推出了專門面向表單級(jí)的增刪改查,聲明即實(shí)現(xiàn)。官方說(shuō)明:https://juejin.cn/post/7033388050012962852 。

          瀏覽 68
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  日韩A片在线 | 爱逼逼网 | 青青操青青操在线视频免费 | 亚洲欧美在线观看久99一区 | 成人AV中文字幕 |