大纲
前言
版本说明
本文的教程内容是基于 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 的分布式事务方案 。
- 提供 本地多数据源事务方案。
框架约定
- 本框架只做 切换数据源 这件核心的事情,并不限制你的具体操作,切换了数据源可以做任何 CRUD。
- 配置文件所有以下划线
_
分割的数据源 首部 即为组的名称,相同组名称的数据源会放在一个组下。
- 切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
- 默认的数据源名称为 master ,你可以通过
spring.datasource.dynamic.primary
修改。
- 方法上的注解优先于类上注解(就近原则)。
- @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_1
与 mysql_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 strict: true 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
| 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
1 2 3
| public interface EmployeeMapper extends BaseMapper<Employee> {
}
|
1 2 3 4 5
| public interface IEmployeeService extends IService<Employee> {
public Page<Employee> queryByPage();
}
|
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
1 2 3
| public interface DepartmentMapper extends BaseMapper<Department> {
}
|
1 2 3 4 5
| public interface IDepartmentService extends IService<Department> {
public Page<Department> queryByPage();
}
|
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: exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure datasource: type: com.alibaba.druid.pool.DruidDataSource dynamic: primary: mysql_1 strict: true 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() .fileOverride() .outputDir("D://"); }).packageConfig(builder -> { builder.parent("com.clay.mybatis") .moduleName("system") .pathInfo(Collections.singletonMap(OutputFile.xml, "D://")); }).strategyConfig(builder -> { builder.addInclude("t_employee") .addTablePrefix("t_"); }).templateEngine(new FreemarkerTemplateEngine()) .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() { GlobalConfig config = new GlobalConfig(); config.setActiveRecord(true) .setAuthor("clay") .setOutputDir("D://") .setFileOverride(true) .setIdType(IdType.AUTO) .setSwagger2(true) .setServiceName("%sService") .setBaseResultMap(true) .setBaseColumnList(true);
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");
StrategyConfig stConfig = new StrategyConfig(); stConfig.setCapitalMode(true) .setNaming(NamingStrategy.underline_to_camel) .setTablePrefix("t_") .setInclude("t_employee");
PackageConfig pkConfig = new PackageConfig(); pkConfig.setParent("com.clay.mybatis") .setModuleName("system") .setMapper("mapper").setService("service").setController("controller").setEntity("beans").setXml("mapper");
AutoGenerator ag = new AutoGenerator(); ag.setGlobalConfig(config).setDataSource(dsConfig).setStrategy(stConfig).setPackageInfo(pkConfig);
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 配置数据源)、更改或重置代码模板,详细使用教程可看 这里。