一、场景描述
本文是单数据源配置的衍生和续篇。关于 MySQL
数据库单数据源的配置,请参考前面 《JAVA 数据库连接池系列 —— Spring Boot 2.x 整合 HikariCP 多数据源
》 这篇文章。
在项目的开发过程中,特别是项目未进行微服务划分的情况下。很有可能出现一个业务请求,需要多个数据库的检索结果进行多次加工后,才能满足本次业务检索需求的场景。但是整个请求都处于同一个项目中。这样,单项目多、数据源的需求就慢慢的被团队成员所需要。
本文主要采用的是苞米豆的动态数据源,具体可以参考开源的文档进行项目集成,本文案例也是基于此文档进行测试。
二、组件介绍
-
特性
-
支持数据源分组 ,适用于多种场景纯粹多库、读写分离、一主多从、混合模式。
-
支持数据库敏感配置信息 加密
ENC()
。 -
支持每个数据库独立初始化表结构
schema
和数据库database
。 -
支持自定义注解 ,需继承
DS(3.2.0+)
。 -
提供对
Druid
,Mybatis-Plus
,P6sy
,Jndi
的快速集成。 -
简化
Druid
和HikariCp
配置,提供全局参数配置。配置一次,全局通用。 -
提供自定义数据源来源方案。
-
提供项目启动后动态增加移除数据源方案。
-
提供
Mybatis
环境下的纯读写分离方案。 -
提供使用 spel动态参数解析数据源 方案。内置
spel
,session
,header
,支持自定义。 -
支持多层数据源嵌套切换。(
ServiceA >>> ServiceB >>> ServiceC
)。 -
提供对
shiro
,sharding-jdbc
,quartz
等第三方库集成的方案,注意事项和示例。 -
提供基于seata的分布式事务方案。 附:不支持原生
spring
事务。 -
提供本地多数据源事务方案。 附:不支持原生
spring
事务。
-
-
约定
-
本框架只做切换数据源这件核心的事情。
-
配置文件所有以下划线
_
分割的数据源首部即为组的名称,相同组名称的数据源会放在一个组下。 -
切换数据源可以是组名,也可以是具体数据源名称。组名则切换时采用负载均衡算法切换。
-
默认的数据源名称为
master
,你可以通过spring.datasource.dynamic.primary
修改。 -
方法上的注解优先于类上注解。
-
三、组件引入
-
依赖版本
<properties> <!-- 2020-07-12 --> <mysql-connector.version>8.0.21</mysql-connector.version> <!-- 2020-10-10 --> <mybatis-plus.version>3.4.1</mybatis-plus.version> <!-- 2020-12-25 --> <mybatis-plus-datasource.version>3.3.1</mybatis-plus-datasource.version> <!-- 2019-11-26 --> <pagehelper.version>1.2.13</pagehelper.version> </properties>
-
主要依赖
<!-- MyBatis-plus 多数据源 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>${mybatis-plus-datasource.version}</version> </dependency>
-
辅助依赖
<!-- MySQL连接驱动依赖 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector.version}</version> </dependency> <!-- MyBaits-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper.version}</version> </dependency>
四、测试案例
-
前置说明
-
本次实验采用两个数据库实例,一个位于腾讯云、一个位于本次开发环境
-
两个数据库实例的测试数据库名称都是
exercise
,数据库中的表也是student
-
通过不同环境的表中的数据来区分不同的环境
-
案例中,在
MAPPER
中添加了DS()
据源的注解,同时在Service
中添加了DS()
数据源的注解,主要是验证多数源是否生效,生效后验证哪个级别的生效。
-
-
引入相关依赖
请参考步骤二中的依赖
-
配置多数据源
spring: # ==================================== 数据源相关配置开始 ===================================== # ==================================== 单数据源配置开始(如果使用单数据源,请删除 pom.xml 文件中的 dynamic-datasource-spring-boot-starter) ===================================== # Hikari pool https://github.com/brettwooldridge/HikariCP # datasource: # name: SPRING-BOOT-SAMPLE-MYSQL # driver-class-name: com.mysql.cj.jdbc.Driver # url: jdbc:mysql://127.0.0.1:3306/exercise?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false # username: ENC(XXXX) # password: ENC(XXXX) # ==================================== 单数据源配置结束 ===================================== # ==================================== 多数据源配置开始 ===================================== datasource: dynamic: primary: TENCENT datasource: TENCENT: name: SPRING-BOOT-SAMPLE-MYSQL-TENCENT driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/exercise?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false username: ENC(XXXX) password: ENC(XXXX RCS: name: SPRING-BOOT-SAMPLE-MYSQL-RCS driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/exercise?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=false username: ENC(XXXX) password: ENC(XXXX) # ==================================== 多数据源配置结束 ===================================== type: com.zaxxer.hikari.HikariDataSource hikari: # 连接池中允许的最小连接数。缺省值:10 minimum-idle: 30 # 连接池中允许的最大连接数。缺省值:10 maximum-pool-size: 100 # 自动提交 auto-commit: true # 一个连接 idle 状态的最大时长(毫秒),超时则被释放(retired),缺省:10分钟 idle-timeout: 30000 # 连接池名字 pool-name: SampleProjectHikairCP # 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),缺省:30分钟,建议设置比数据库超时时长少30秒 max-lifetime: 1800000 # 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 缺省:30秒 connection-timeout: 30000 # 数据库连接测试语 connection-test-query: SELECT 1 # ==================================== 数据源相关配置结束 ===================================== # ==================================== 数据库插件配置开始 ===================================== mybatis-plus: # 一定要对应mapper映射xml文件的所在路径 mapper-locations: classpath:mapping/**/*.xml # 对应实体类的路径 type-aliases-package: com.rambo.springbootsample.model global-config: banner: false pagehelper: helper-dialect: mysql reasonable: true support-methods-arguments: true params: count=countSql return-page-info: check # ==================================== 数据库插件配置结束 =====================================
-
创建
DAO
层的数据库操作@DS("TENCENT") public interface StudentExtMapper extends StudentMapper { /** * 根据名字查询学生信息 * * @author Rambo * @date 2021/1/11 10:31 * @param name 学生姓名 * @return com.rambo.springbootsample.model.Student */ List<Student> queryStudentByName(@Param("name") String name); }
-
创建
Service
的服务类@Service @DS("RCS") public class StudentServiceImpl implements StudentService { @Resource private StudentExtMapper studentExtMapper; @Override public DataResult<List<Student>> queryStudentByName(String name) { if (StringUtils.isEmpty(name)) { throw new BusinessException(ModuleServiceResponseCode.MODULE_2001); } List<Student> result = studentExtMapper.queryStudentByName(name); return DataResult.getDataResult(result); } }
-
创建
Controller
对外暴露接口@RestController @RequestMapping("/dynamic") @Slf4j @Api(tags = "动态数据源演示——控制器") public class DynamicDatasourceDemoController { @Resource private StudentService studentService; @GetMapping("/student") @ApiOperation(value = "根据姓名获取学生信息") public DataResult<List<Student>> student (@RequestParam(value = "name") String name) { return studentService.queryStudentByName(name); } }
-
验证测试结果
-
在
Service
和Mapper
中都配置来DS
数据源,默认执行的是最底层(Mapper
) 所指定的数据源
-
去除
Mapper
中配置的DS
数据源,则执行来Service
中所指定的数据源
-
如果配置了多个
DS
指定数据源,则以最接近数据库操作的层为有效