本文是向大家介绍Fluent Mybatis ,其实不是介绍,如果只是简单介绍,官方文档足够了。而是实战深入,比较适合已经有一定了解FluentMybatis的同学。
它能够实现多数据源接入,不使用默认傻瓜式配置,避免泛泛而谈,似是而非,转眼就忘
能够带来深入理解FluentMybatis的使用价值。
有兴趣的同学,不妨考虑适配Sharding-jdbc,Zdal-jdbc,组合使用,刚好可以锻炼提升一下
前言: 什么是Fluent Mybatis
简单入门: 地址

和其他plus 框架比较
- | Mybatis Plus | Fluent Mybatis |
代码生成 | 生成 Entity, Mapper, Wrapper等文件, 并且Generator很好用 | 只生成Entity, 再通过编译生成 Mapper, Query, Update 和 SqlProvider |
和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语法渲染, 可读性更高 |
1. 配置案例

1.1 pom依赖jar包
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<commons.version>2.6</commons.version>
<druid.version>1.1.17</druid.version>
<fluent-mybatis.version>1.8.7</fluent-mybatis.version>
<mysql.connector.version>8.0.17</mysql.connector.version>
</properties>
<!-- 引入fluent-mybatis 运行依赖包, scope为compile -->
<dependency>
<groupId>com.github.atool</groupId>
<artifactId>fluent-mybatis</artifactId>
<version>${fluent-mybatis.version}</version>
</dependency>
<!-- 引入fluent-mybatis-processor, scope设置为provider 编译需要,运行时不需要 -->
<dependency>
<groupId>com.github.atool</groupId>
<artifactId>fluent-mybatis-processor</artifactId>
<scope>provided</scope>
<version>${fluent-mybatis.version}</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!--Caused by: java.lang.annotation.AnnotationFormatError:
Invalid default: public abstract java.lang.Class org.mybatis.spring.annotation.MapperScan.factoryBean()-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>1.2 数据源 注解配置
package com.csu.andrew.fluentmybatisdemo.common.config;
import cn.org.atool.fluent.mybatis.spring.MapperFactory;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* @author zhangcq
* @version 1.0.0
* @title
* @date 2021/8/12 10:34
*/
@Configuration
@MapperScan(basePackages = "com.csu.andrew.fluentmybatisdemo.commondao.mapper", sqlSessionFactoryRef = "mgportraitbasecoreSqlSessionFactory")
@MapperScan(basePackages = "com.csu.andrew.fluentmybatisdemo.anotherdao.mapper", sqlSessionFactoryRef = "anotherSqlSessionFactory")
public class DataSourceCfg {
@Bean(initMethod = "init")
@Primary
@ConfigurationProperties(prefix = "custom.datasource1.druid")
public DruidDataSource getPrimaryDataSource() {
return new DruidDataSource();
}
@Bean("mgportraitbasecoreSqlSessionFactory")
@Primary
@Autowired
public SqlSessionFactoryBean sqlSessionFactoryBean(DruidDataSource druidDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(druidDataSource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// 路径正则表达式方式加载
bean.setMapperLocations(resolver.getResources("classpath*:mapper/*.xml"));
// 一个个文件加载
// bean.setMapperLocations(
// new ClassPathResource("mapper/MyXmlMapper.xml"),
// new ClassPathResource("mapper/BatchUpdate.xml")
// );
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLazyLoadingEnabled(true);
configuration.setMapUnderscoreToCamelCase(true);
bean.setConfiguration(configuration);
return bean;
}
@Bean(initMethod = "init", value = "anotherDataSource")
@ConfigurationProperties(prefix = "custom.datasource2.druid")
public DruidDataSource getAnotherDataSource() {
return new DruidDataSource();
}
@Bean("anotherSqlSessionFactory")
@Autowired
public SqlSessionFactoryBean sqlSessionFactoryAnotherBean(@Qualifier("anotherDataSource") DruidDataSource druidDataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(druidDataSource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// 路径正则表达式方式加载
bean.setMapperLocations(resolver.getResources("classpath*:anothermapper/*.xml"));
// 一个个文件加载
// bean.setMapperLocations(
// new ClassPathResource("mapper/MyXmlMapper.xml"),
// new ClassPathResource("mapper/BatchUpdate.xml")
// );
org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
configuration.setLazyLoadingEnabled(true);
configuration.setMapUnderscoreToCamelCase(true);
bean.setConfiguration(configuration);
return bean;
}
@Bean
public MapperFactory mapperFactory() {
return new MapperFactory();
}
}
1.3 application.properties 配置
# 应用名称
spring.application.name=fluent-mybatisdemo
# 应用服务 WEB 访问端口
server.port=8080
custom.db.ipport=dbserver:3306
custom.db.name=testdb
custom.db.user=**
custom.db.pass=***
custom.datasource1.druid.url=jdbc:mysql://${custom.db.ipport}/${custom.db.name}?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
custom.datasource1.druid.username=${custom.db.user}
custom.datasource1.druid.password=${custom.db.pass}
custom.datasource1.druid.driver-class-name=com.mysql.cj.jdbc.Driver
custom.datasource2.druid.url=jdbc:mysql://${custom.db.ipport}/ry-vue?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
custom.datasource2.druid.username=***
custom.datasource2.druid.password=***
custom.datasource2.druid.driver-class-name=com.mysql.cj.jdbc.Driver2. 测试验证代码
@RestController
public class UserProvincePrecheckJobController {
@Autowired
SysDictDataDao sysDictDataDao;
@Autowired
UserProvincePrecheckJobDao userProvincePrecheckJobDao;
@GetMapping(value = "/test1")
@ResponseBody
public List<UserProvincePrecheckJobDo> getUserProvincePrecheckJobDo() {
return userProvincePrecheckJobDao.list();
}
@GetMapping(value = "/test2")
@ResponseBody
public List<SysDictDataDo> getSysDictDataDo() {
return sysDictDataDao.list();
}
}2.1 验证数据源 testdb中的UserProvincePrecheckJobDo

2.2 验证数据源 ry-vue 中的 SysDictDataDo
