使用fluent mybatis可以不用写具体的xml文件,通过java api可以构造出比较复杂的业务sql语句,做到代码逻辑和sql逻辑的合一。不再需要在Dao中组装查询或更新操作,在xml或mapper中再组装参数。那对比原生Mybatis, Mybatis Plus或者其他框架,FluentMybatis提供了哪些便利呢?

需求场景设置

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

idbigint
 auto_increment 
comment'主键ID'
 primary 
key
,

    student_id   
bigintnotnullcomment'学号'
,

    gender_man   
tinyintdefault0notnullcomment'性别, 0:女; 1:男'
,

    school_term  
intnullcomment'学期'
,

    subject      
varchar
(
30
)       
nullcomment'学科'
,

    score        
intnullcomment'成绩'
,

    gmt_create   datetime          
notnullcomment'记录创建时间'
,

    gmt_modified datetime          
notnullcomment'记录最后修改时间'
,

    is_deleted   
tinyintdefault0notnullcomment'逻辑删除标识'
engine
 = 
InnoDBdefaultcharset
=utf8;


现在有需求:
统计2000年三门学科('英语', '数学', '语文')及格分数按学期,学科统计最低分,最高分和平均分, 且样本数需要大于1条,统计结果按学期和学科排序
我们可以写SQL语句如下
select
 school_term,

       subject,

count
(score) 
ascount
,

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
groupby
 school_term, subject

havingcount
(score) > 
1
orderby
 school_term, subject;


那上面的需求,分别用fluent mybatis, 原生mybatis 和 Mybatis plus来实现一番。
基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
  • 项目地址:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

三者实现对比

使用fluent mybatis 来实现上面的功能

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

换成mybatis原生实现效果

  1. 定义Mapper接口
publicinterfaceMyStudentScoreMapper
{

    List<Map<String, Object>> summaryScore(SummaryQuery paras);

}


  1. 定义接口需要用到的参数实体 SummaryQuery
@Data
@Accessors
(chain = 
true
)

publicclassSummaryQuery
{

private
 Integer schoolTerm;


private
 List<String> subjects;


private
 Integer score;


private
 Integer minCount;

}


  1. 定义实现业务逻辑的mapper xml文件
<selectid="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

<foreachcollection="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>

  1. 实现业务接口(这里是测试类, 实际应用中应该对应Dao类)
@RunWith
(SpringRunner
.
class
)

@
SpringBootTest
(
classes
= QuickStartApplication
.
class
)

publicclassMybatisDemo
{

@Autowired
private
 MyStudentScoreMapper mapper;


@Test
publicvoidmybatis_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要弱,就不再比较了。
基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
  • 项目地址:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

生成代码编码比较

fluent mybatis生成代码设置

publicclassAppEntityGenerator
{

staticfinal
 String url = 
"jdbc:mysql://localhost:3306/fluent_mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8"
;


publicstaticvoidmain(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"
})

    )

staticclassAbc
{

    }

}


mybatis plus代码生成设置

publicclassCodeGenerator
{


static
 String dbUrl = 
"jdbc:mysql://localhost:3306/fluent_mybatis_demo?useSSL=false&useUnicode=true&characterEncoding=utf-8"
;


@Test
publicvoidgenerateCode()
{

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

    }

}


FluentMybatis特性一览

三者对比总结

看完3个框架对同一个功能点的实现, 各位看官肯定会有自己的判断,笔者这里也总结了一份比较。
-Mybatis PlusFluent Mybatis
代码生成生成 Entity生成Entity, 再通过编译生成 Mapper, Query, Update 和 SqlProvider
Generator易用性
和Mybatis的共生关系需替换原有的SqlSessionFactoryBean对Mybatis没有任何修改,原来怎么用还是怎么用
动态SQL构造方式应用启动时, 根据Entity注解信息构造动态xml片段,注入到Mybatis解析器应用编译时,根据Entity注解,编译生成对应方法的SqlProvider,利用mybatis的Mapper上@InsertProvider @SelectProvider @UpdateProvider注解关联
动态SQL结果是否容易DEBUG跟踪不容易debug容易,直接定位到SQLProvider方法上,设置断点即可
动态SQL构造通过硬编码字段名称, 或者利用Entity的get方法的lambda表达式通过编译手段生成对应的方法名,直接调用方法即可
字段变更后的错误发现通过get方法的lambda表达的可以编译发现,通过字段编码的无法编译发现编译时便可发现
不同字段动态SQL构造方法通过接口参数方式通过接口名称方式, FluentAPI的编码效率更高
语法渲染特点通过关键变量select, update, set, and, or可以利用IDE语法渲染, 可读性更高


欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,
长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。
提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
继续阅读
阅读原文