前言

日常开发中,可能会遇到一个项目要调用多个数据源的情况,比如同一个 MySQL 不同的库,也可能是从不同的 MySQL 进行获取数据,此时,我们可以使用 dynamic datasource 进行多数据源切换。

dynamic datasource 介绍

dynamic datasource 其实是 苞米豆(也就是 MyBatis-Plus)的其中一个框架,是一个基于 Spring Boot 的快速集成多数据源的启动器。

更详细的了解,请前往 dynamic datasource 官网

快速开始

演示环境

  • IntelliJ IDEA 2020.3.2
  • JDK 8
  • MySQL 5.7
  • Maven 3.6.3
  • Spring Boot 2.4.5

SQL 准备(创建了两个库,分别是 depemp

dep 库下的表

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE `t_dep` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of t_dep
-- ----------------------------
INSERT INTO `t_dep` VALUES ('1', '開發部');
INSERT INTO `t_dep` VALUES ('2', '測試部');
INSERT INTO `t_dep` VALUES ('3', '生產部');

emp 库下的表

1
2
3
4
5
6
7
8
9
10
11
12
CREATE TABLE `t_emp` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of t_emp
-- ----------------------------
INSERT INTO `t_emp` VALUES ('1', '張三');
INSERT INTO `t_emp` VALUES ('2', '李四');
INSERT INTO `t_emp` VALUES ('3', '王五');

然后创建 Spring Boot 项目,引入基本的 Web 依赖和 MySQL 驱动

完整的 pom 文件

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
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--dynamic datasource 核心 maven 依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

编写配置文件(application.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
datasource:
dynamic:
primary: master # 设置默认的数据源或者数据源组,默认值即为 master
strict: false # 设置严格模式,默认 false 不启动. 启动后在未匹配到指定数据源时候会抛出异常,不启动则使用默认数据源.
datasource:
master:
url: jdbc:mysql:///dep
username: garvey
password: root
driver-class-name: com.mysql.jdbc.Driver
slave:
url: jdbc:mysql:///emp
username: garvey
password: root
driver-class-name: com.mysql.jdbc.Driver

dao 层(因为就这么一句简单 SQL,这里就不创建 mapper 映射文件了,直接使用注解)

1
2
3
4
5
6
7
8
9
10
11
public interface DepMapper {

@Select("SELECT id, name FROM t_dep")
List<Dep> selectAll();
}

public interface EmpMapper {

@Select("SELECT id, name FROM t_emp")
List<Emp> selectAll();
}

实体类就没什么好讲的了

然后就可以通过 @DS 注解进行切换数据源。

@DS 注解可以作用在方法上也可以作用在类上,同时存在就近原则,方法上的注解优先于类上的注解

注解结果
没有 @DS默认数据源
@DS(“dsName”)dsName 可以为组名也可以为具体某个库的名称
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Service
@DS("master")
public class TestService {

@Autowired
private DepMapper depMapper;

@Autowired
private EmpMapper empMapper;

public List<Dep> selectDepAll() {
return depMapper.selectAll();
}

@DS("slave")
public List<Emp> selectEmpAll() {
return empMapper.selectAll();
}
}

在启动类中加上扫描 Mapper 接口的注解,最后创建 Controller 进行测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RestController
public class TestController {

@Autowired
private TestService testService;

@GetMapping("dep")
public Object dep() {
return testService.selectDepAll();
}

@GetMapping("emp")
public Object emp() {
return testService.selectEmpAll();
}
}

启动之后,打开浏览器分别访问

http://localhost:8080/dep

http://localhost:8080/emp

images

参考文档