MyBatis-Plus 入门教程之七

大纲

前言

版本说明

本文的教程内容是基于 MyBatis-Plus 3.5.2 版本编写的,若你使用的是 2.x 或其他版本,可能会有部分知识点、案例代码不兼容,一切以 MyBatis-Plus 官方文档为准。

MyBatis-Plus 多数据源

dynamic-datasource 是一个基于 SpringBoot 的快速集成多数据源的启动器,支持多数据源(动态数据源),适用于纯粹多库、读写分离、一主多从、混合模式的使用场景。

框架特性

  • 支持 数据源分组 ,适用于多种场景:纯粹多库、读写分离、一主多从、混合模式。
  • 支持数据库敏感配置信息 加密 (可自定义) ENC()。
  • 支持每个数据库独立初始化表结构 schema 和数据库 database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承 DS(3.2.0+)。
  • 提供并简化对 Druid,HikariCp,BeeCp,Dbcp2 的快速集成。
  • 提供对 Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi 等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供 Mybatis 环境下的 纯读写分离 方案。
  • 提供使用 spel 动态参数 解析数据源方案。内置 spel,session,header,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  • 提供 基于 Seata 的分布式事务方案
  • 提供 本地多数据源事务方案。

框架约定

    1. 本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何 CRUD。
    1. 配置文件所有以下划线 _ 分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
    1. 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
    1. 默认的数据源名称为 master ,你可以通过 spring.datasource.dynamic.primary 修改。
    1. 方法上的注解优先于类上注解(就近原则)。
    1. @DS 支持继承抽象类上的 @DS,暂不支持继承接口上的 @DS。

@DS 注解

@DS 用于动态切换数据源,可以注解在方法上或类上,同时存在时方法上的注解优先于类上的注解(就近原则)

注解结果
没有 @DS 注解使用默认的数据源
@DS("dsName")dsName 可以为组名,也可以为具体某个数据源的名称

多数据源使用案例

这里模拟纯粹多库的使用场景,其他场景的使用方法与之类似。本节所需的案例代码,可以直接从 GitHub 下载对应章节 mybatis-plus-lesson-13

创建多个数据库

  • 创建数据库 mybatis_plus_database_1,并创建 t_employee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
CREATE DATABASE `mybatis_plus_database_1` DEFAULT CHARACTER SET utf8mb4;

USE `mybatis_plus_database_1`;

CREATE TABLE `t_employee` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`last_name` varchar(255) DEFAULT NULL,
`gender` char(1) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`age` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into t_employee(id, last_name, gender, email, age) values(1, 'Jim','1', 'jim@gmail.com', 26), (2, 'Peter','1', 'peter@gmail.com', 29);
  • 创建数据库 mybatis_plus_database_2,并创建 t_department
1
2
3
4
5
6
7
8
9
10
11
12
CREATE DATABASE `mybatis_plus_database_2` DEFAULT CHARACTER SET utf8mb4;

USE `mybatis_plus_database_2`;

CREATE TABLE `t_department` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`deleted` int DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert into t_department(id, name, deleted) values(1, '开发部门', 0), (2, '测试部门', 0), (3, '产品部', 0);

引入 Maven 依赖

若在 SpringBoot 项目中已经整合好 MyBatis 与 MyBatis-Plus,则只需要引入以下 Starter 即可使用动态数据源。值得一提的是,SpringBoot 整合 MyBatis 与 MyBatis-Plus 的详细教程可查看 这里

1
2
3
4
5
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>

添加多数据源配置

在下述的配置内容中,分别定义了数据源 mysql_1mysql_2,其中的 mysql_1 是默认的数据源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
datasource:
dynamic:
primary: mysql_1 # 设置默认的数据源或者数据源组,默认值为 master
strict: true # 严格匹配数据源,默认false。设置为 true 未匹配到指定数据源时抛异常,false 使用默认数据源
datasource:
mysql_1:
url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_database_1?characterEncoding=utf8&autoReconnect=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mysql_2:
url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_database_2?characterEncoding=utf8&autoReconnect=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver

其他场景的配置示例

1
2
3
4
5
6
7
8
9
10
# 多主多从                      纯粹多库(记得设置primary)                   混合配置
spring: spring: spring:
datasource: datasource: datasource:
dynamic: dynamic: dynamic:
datasource: datasource: datasource:
master_1: mysql: master:
master_2: oracle: slave_1:
slave_1: sqlserver: slave_2:
slave_2: postgresql: oracle_1:
slave_3: h2: oracle_2:

使用 @DS 注解切换数据源

创建员工的 Mapper 与 Service
  • Mapper 接口
1
2
3
public interface EmployeeMapper extends BaseMapper<Employee> {

}
  • Service 接口
1
2
3
4
5
public interface IEmployeeService extends IService<Employee> {

public Page<Employee> queryByPage();

}
  • Service 实现类,使用 @DS 注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
@DS("mysql_1")
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {

@Override
public Page<Employee> queryByPage() {
Page<Employee> page = new Page<>(1, 10);
QueryWrapper<Employee> wrapper = new QueryWrapper<>();
wrapper.like("last_name", "i");
baseMapper.selectPage(page, wrapper);
return page;
}

}
创建部门的 Mapper 与 Service
  • Mapper 接口
1
2
3
public interface DepartmentMapper extends BaseMapper<Department> {

}
  • Service 接口
1
2
3
4
5
public interface IDepartmentService extends IService<Department> {

public Page<Department> queryByPage();

}
  • Service 实现类,使用 @DS 注解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Service
@DS("mysql_2")
public class DepartmentServiceImpl extends ServiceImpl<DepartmentMapper, Department> implements IDepartmentService {

@Override
public Page<Department> queryByPage() {
Page<Department> page = new Page<>(1, 10);
QueryWrapper<Department> wrapper = new QueryWrapper<>();
wrapper.like("name", "开发");
baseMapper.selectPage(page, wrapper);
return page;
}

}

Junit 单元测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@SpringBootTest
public class MyBatisPlusApplicationTest {

@Autowired
private IEmployeeService empService;

@Autowired
private IDepartmentService deptService;

@Test
public void dynamicDataSource() {
Page<Employee> empPage = empService.queryByPage();
List<Employee> empList = empPage.getRecords();
empList.forEach(System.out::println);

Page<Department> deptPage = deptService.queryByPage();
List<Department> deptList = deptPage.getRecords();
deptList.forEach(System.out::println);
}

}

执行上面的测试代码后,控制台输出的日志信息如下,则说明动态数据源的配置生效了。

1
2
3
4
5
6
7
8
9
10
11
12
13
==>  Preparing: SELECT id,email,last_name,gender,age FROM t_employee WHERE (last_name LIKE ?)
==> Parameters: %i%(String)
<== Columns: id, email, last_name, gender, age
<== Row: 1, jim@gmail.com, Jim, 1, 26
<== Total: 1
Employee [id=1, lastName=Jim, gender=1, email=jim@gmail.com, age=26]

==> Preparing: SELECT id,name,deleted FROM t_department WHERE deleted=0 AND (name LIKE ?)
==> Parameters: %开发%(String)
<== Columns: id, name, deleted
<== Row: 1, 开发部门, 0
<== Total: 1
Department [id=1, name=开发部门, deleted=0]

整合 Druid 连接池

引入 Maven 依赖

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.11</version>
</dependency>

配置 Druid 连接池

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
spring:
autoconfigure:
# 排除 Druid 自动配置
exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
datasource:
# 指定使用 Druid 数据源
type: com.alibaba.druid.pool.DruidDataSource
dynamic:
primary: mysql_1 # 设置默认的数据源或者数据源组,默认值为 master
strict: true # 严格匹配数据源,默认false。设置为 true 未匹配到指定数据源时抛异常,false 使用默认数据源
datasource:
mysql_1:
url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_database_1?characterEncoding=utf8&autoReconnect=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mysql_2:
url: jdbc:mysql://127.0.0.1:3306/mybatis_plus_database_2?characterEncoding=utf8&autoReconnect=true&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
initialSize: 5
minIdle: 5
maxActive: 30
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,slf4j,config
useGlobalDataSourceStat: true
stat-view-servlet:
enabled: false
url-pattern: /druid/*
login-username: admin
login-password: 123456
filter:
stat:
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true

MyBatis-Plus 代码生成器

代码生成器介绍

MyBatis-Plus 的代码生成器,可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大地提升了开发效率。值得一提的是,MyBatis-Plus 的代码生成器是基于 Java 代码来生成的,而 MyBatis-Generator(MBG) 是基于 XML 配置文件进行代码生成的。

IDEA 插件 MybatisX

  • 1、MyBatis-Plus 除了支持通过 Java 代码来生成各个模块的代码之外,还支持使用官方的 IDEA 插件 MybatisX,通过 GUI 界面的方式来快速生成代码。
  • 2、MybatisX IDEA 插件支持 XML 跳转、生成 Java 代码与 SQL 映射文件(需要先在 IDEA 中的 Database 配置数据源)、更改或重置代码模板,详细使用教程可看 这里

代码生成器使用案例(新版)

本节所需的案例代码,可以直接从 GitHub 下载对应章节 mybatis-plus-lesson-12

Maven 依赖

MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl、Enjoy 模板引擎,用户可以选择自己熟悉的模板引擎(直接引入依赖即可)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.5.2</version>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.2</version>
</dependency>

<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>

加入 SLF4J 依赖(可选),方便查看输出的日志信息

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
</dependency>

快速生成代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class GeneratorCodeTest {

/**
* 数据源配置
*/
private static final DataSourceConfig.Builder DATA_SOURCE_CONFIG = new DataSourceConfig.Builder("jdbc:mysql://127.0.0.1:3306/mybatis_plus_lesson?characterEncoding=utf8&useSSL=false", "root", "123456");

/**
* 快速生成
*/
@Test
public void generatorCode() {
FastAutoGenerator.create(DATA_SOURCE_CONFIG).globalConfig(builder -> {
builder.author("clay") // 设置作者
.enableSwagger() // 开启Swagger2模式
.fileOverride() // 覆盖已生成文件
.outputDir("D://"); // 指定输出目录
}).packageConfig(builder -> {
builder.parent("com.clay.mybatis") // 设置父包名
.moduleName("system") // 设置模块名
.pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); // 设置SQL映射文件的生成路径
}).strategyConfig(builder -> {
builder.addInclude("t_employee") // 设置需要生成的表名
.addTablePrefix("t_"); // 设置过滤表前缀
}).templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认使用的是Velocity引擎模板
.execute();

}

}

执行上面的测试代码后,控制台输出的日志信息如下:

1
2
3
4
5
6
7
21:04:25.308 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================准备生成文件...==========================
21:04:25.862 [main] DEBUG com.baomidou.mybatisplus.generator.config.querys.MySqlQuery - 执行SQL:show table status WHERE 1=1 AND NAME IN ('t_employee')
21:04:25.901 [main] DEBUG com.baomidou.mybatisplus.generator.config.querys.MySqlQuery - 返回记录数:1,耗时(ms):37
21:04:25.928 [main] DEBUG com.baomidou.mybatisplus.generator.config.querys.MySqlQuery - 执行SQL:show full fields from `t_employee`
21:04:25.941 [main] DEBUG com.baomidou.mybatisplus.generator.config.querys.MySqlQuery - 返回记录数:5,耗时(ms):12
21:04:26.255 [main] DEBUG com.baomidou.mybatisplus.generator.util.RuntimeUtils - 文件输出目录:D://
21:04:26.255 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================文件生成完成!!!==========================

代码生成后的目录机构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
├── com
│   └── clay
│   └── mybatis
│   └── system
│   ├── controller
│   │   └── EmployeeController.java
│   ├── entity
│   │   └── Employee.java
│   ├── mapper
│   │   └── EmployeeMapper.java
│   └── service
│   ├── IEmployeeService.java
│   └── impl
│   └── EmployeeServiceImpl.java
└── EmployeeMapper.xml

代码生成器使用案例(旧版)

Maven 依赖

MyBatis-Plus 支持 Velocity(默认)、Freemarker、Beetl、Enjoy 模板引擎,用户可以选择自己熟悉的模板引擎(直接引入依赖即可)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>3.0.1</version>
</dependency>

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.0.1</version>
</dependency>

<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.31</version>
</dependency>

加入 SLF4J 依赖(可选),方便查看输出的日志信息

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.36</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.36</version>
</dependency>

快速生成代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class GeneratorCodeTest {

/**
* 快速生成
*/
@Test
public void generatorCode() {
// 1. 全局配置
GlobalConfig config = new GlobalConfig();
config.setActiveRecord(true) // 是否支持AR模式
.setAuthor("clay") // 作者
.setOutputDir("D://") // 生成路径
.setFileOverride(true) // 文件覆盖
.setIdType(IdType.AUTO) // 主键策略
.setSwagger2(true) // 开启Swagger2模式
.setServiceName("%sService") // 设置生成的Service接口的名字的首字母是否为I,例如IService
.setBaseResultMap(true) // 生成通用查询映射结果(ResultMap)
.setBaseColumnList(true); // 生成通用查询结果列(SQL 片段)

// 2. 数据源配置
DataSourceConfig dsConfig = new DataSourceConfig();
dsConfig.setDbType(DbType.MYSQL) // 数据库类型
.setDriverName("com.mysql.jdbc.Driver").setUrl("jdbc:mysql://127.0.0.1:3306/mybatis_plus_lesson?characterEncoding=utf8&useSSL=false").setUsername("root").setPassword("123456");

// 3. 策略配置
StrategyConfig stConfig = new StrategyConfig();
stConfig.setCapitalMode(true) // 全局大写命名
.setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略
.setTablePrefix("t_") // 过滤表前缀
.setInclude("t_employee"); // 需要生成的表名

// 4. 包名策略配置
PackageConfig pkConfig = new PackageConfig();
pkConfig.setParent("com.clay.mybatis") // 设置父包名
.setModuleName("system") // 设置模块名
.setMapper("mapper").setService("service").setController("controller").setEntity("beans").setXml("mapper");

// 5. 整合配置
AutoGenerator ag = new AutoGenerator();
ag.setGlobalConfig(config).setDataSource(dsConfig).setStrategy(stConfig).setPackageInfo(pkConfig);

// 6. 执行
ag.execute();
}

}

执行上面的测试代码后,控制台输出的日志信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
22:32:15.776 [main] DEBUG org.apache.velocity.rendering - =================================================================
22:32:15.778 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/entity.java.vm; 文件:D://com/clay/mybatis/system/beans/Employee.java
22:32:15.780 [main] DEBUG org.apache.velocity.loader - ResourceManager: found /templates/mapper.java.vm with loader org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
22:32:15.781 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/mapper.java.vm; 文件:D://com/clay/mybatis/system/mapper/EmployeeMapper.java
22:32:15.784 [main] DEBUG org.apache.velocity.loader - ResourceManager: found /templates/mapper.xml.vm with loader org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
22:32:15.788 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/mapper.xml.vm; 文件:D://com/clay/mybatis/system/mapper/EmployeeMapper.xml
22:32:15.790 [main] DEBUG org.apache.velocity.loader - ResourceManager: found /templates/service.java.vm with loader org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
22:32:15.790 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/service.java.vm; 文件:D://com/clay/mybatis/system/service/EmployeeService.java
22:32:15.792 [main] DEBUG org.apache.velocity.loader - ResourceManager: found /templates/serviceImpl.java.vm with loader org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
22:32:15.793 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/serviceImpl.java.vm; 文件:D://com/clay/mybatis/system/service/impl/EmployeeServiceImpl.java
22:32:15.795 [main] DEBUG org.apache.velocity.loader - ResourceManager: found /templates/controller.java.vm with loader org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader
22:32:15.796 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 模板:/templates/controller.java.vm; 文件:D://com/clay/mybatis/system/controller/EmployeeController.java
22:32:15.796 [main] DEBUG com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine - 文件输出目录:D://
22:32:15.796 [main] DEBUG com.baomidou.mybatisplus.generator.AutoGenerator - ==========================文件生成完成!!!==========================

代码生成后的目录机构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
└── com
└── clay
└── mybatis
└── system
├── beans
│   └── Employee.java
├── controller
│   └── EmployeeController.java
├── mapper
│   ├── EmployeeMapper.java
│   └── EmployeeMapper.xml
└── service
├── EmployeeService.java
└── impl
└── EmployeeServiceImpl.java

MyBatisX IDEA 插件

  • MyBatis-Plus 除了支持通过 Java 代码来生成各个模块的代码之外,还支持使用官方的 IDEA 插件 MybatisX,通过 GUI 界面的方式来快速生成代码。
  • MybatisX IDEA 插件支持 XML 跳转、生成 Java 代码与 SQL 映射文件(需要先在 IDEA 中的 Database 配置数据源)、更改或重置代码模板,详细使用教程可看 这里