SpringBoot配置多数据源(动态切换)
目录
- 前言
- 项目搭建
- 主要工具版本
- 数据准备
- `pom.xml` 依赖
- `application.properties` 配置文件
- 主从数据源的配置类
- 主数据源
- 从数据源
- 项目目录结构
- 实体类
- `dao` 层
- `service` 层
- `Controller` 层
- 测试
- 主数据源测试
- 从数据源测试
前言
随着业务的不断增加,我们的系统会越来越庞大。显然单个数据库已经承受不了高并发带来的压力。一个项目使用多个数据库(无论是主从复制- - 读写分离还是分布式数据库结构)的重要性变得越来越明显。整合多数据源有两种方法:分包 和 AOP
- 分包:分包主要是根据业务划分
AOP
:实际上就是通过AOP
进行拦截,不同的注解里面的值,指向不同的数据源
项目搭建
主要工具版本
SpringBoot
:2.0.6.RELEASE
JDK
:1.8
MySQL
:5.7
数据准备
创建 test1
和 test2
两个库,分别建表 emp
(数据不相同)
test1
作为主库,test2
作为从库- 主库用于写操作,从库用于读操作
CREATE TABLE `emp` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(255) DEFAULT NULL,`age` int(11) DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
test1
库中的表 emp
数据如下
test2
库中的表 emp
数据如下
pom.xml
依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
<!--mysql 驱动-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.38</version>
</dependency>
<!-- druid 数据库连接池 -->
<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version>
</dependency>
<!-- mybatis -->
<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.3.2</version>
</dependency>
<!--lombok 插件-->
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.12</version><scope>provided</scope>
</dependency>
<!--api接口文档可视化 swagger-->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.9.2</version>
</dependency>
<dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.9.2</version>
</dependency>
application.properties
配置文件
server.port=8080#主数据源test1配置
spring.datasource.test1.url=jdbc:mysql://127.0.0.1:3306/test1?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTC
spring.datasource.test1.username=root
spring.datasource.test1.password=123456
spring.datasource.test1.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.test1.type=com.alibaba.druid.pool.DruidDataSource#主数据源test1连接池配置
spring.datasource.druid.test1.initial-size=3
spring.datasource.druid.test1.min-idle=3
spring.datasource.druid.test1.max-active=10
spring.datasource.druid.test1.max-wait=60000#从数据源test2配置
spring.datasource.test2.url=jdbc:mysql://127.0.0.1:3306/test2?characterEncoding=utf8&useSSL=false&autoReconnect=true&serverTimezone=UTC
spring.datasource.test2.username=root
spring.datasource.test2.password=123456
spring.datasource.test2.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.test2.type=com.alibaba.druid.pool.DruidDataSource#从数据源test2连接池配置
spring.datasource.druid.test2.initial-size=3
spring.datasource.druid.test2.min-idle=3
spring.datasource.druid.test2.max-active=10
spring.datasource.druid.test2.max-wait=60000mybatis.configuration.cache-enabled=true
#开启驼峰命名
mybatis.configuration.map-underscore-to-camel-case=true
#打印 SQL 语句
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
url
:此处使用的是url
,不是jdbc-url
。因为下面的配置类中使用的是DruidDataSourceBuilder
构建数据源,而不是使用DataSourceBuilder
构建数据源- 使用
DruidDataSourceBuilder
构建数据源,使用的数据库连接池是druid
- 使用
DataSourceBuilder
构建数据源,使用的数据库连接池是springboot
默认的HikariCP
SpringBoot
的启动类中也并没有exclude = DataSourceAutoConfiguration.class
主从数据源的配置类
主数据源
@Configuration
/*扫描mybatis的接口位置*/
@MapperScan(basePackages = "org.example.test1.mapper", sqlSessionFactoryRef = "test1SqlSessionFactory")
public class DataSourceConfig1 {@Primary /*表示这个数据源是默认主数据源*/@Bean(name = "test1DataSource")@ConfigurationProperties(prefix = "spring.datasource.test1")public DataSource getDateSource1() {return DruidDataSourceBuilder.create().build();}@Primary@Bean(name = "test1SqlSessionFactory")public SqlSessionFactory test1SqlSessionFactory(@Qualifier("test1DataSource") DataSource datasource) throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(datasource);bean.setMapperLocations(/*设置 mybatis 的 xml 所在位置*/new PathMatchingResourcePatternResolver().getResources("classpath:org/example/test1/mapper/*.xml"));return bean.getObject();}@Primary@Bean("test1SqlSessionTemplate")public SqlSessionTemplate test1sqlsessiontemplate(@Qualifier("test1SqlSessionFactory") SqlSessionFactory sessionfactory) {return new SqlSessionTemplate(sessionfactory);}
}
@Primary
:这个注解必须要加,因为不加的话spring
将分不清楚哪个为主数据源(默认数据源)
从数据源
@Configuration
@MapperScan(basePackages = "org.example.test2.mapper", sqlSessionFactoryRef = "test2SqlSessionFactory")
public class DataSourceConfig2 {@Bean(name = "test2DataSource")@ConfigurationProperties(prefix = "spring.datasource.test2")public DataSource getDateSource2() {return DruidDataSourceBuilder.create().build();}@Bean(name = "test2SqlSessionFactory")public SqlSessionFactory test2SqlSessionFactory(@Qualifier("test2DataSource") DataSource datasource)throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(datasource);bean.setMapperLocations(/*设置 mybatis 的 xml 所在位置*/new PathMatchingResourcePatternResolver().getResources("classpath:org/example/test2/mapper/*.xml"));return bean.getObject();}@Bean("test2SqlSessionTemplate")public SqlSessionTemplate test2sqlsessiontemplate(@Qualifier("test2SqlSessionFactory") SqlSessionFactory sessionfactory) {return new SqlSessionTemplate(sessionfactory);}
}
项目目录结构
实体类
@Data
@ApiModel
public class Emp implements Serializable {@ApiModelProperty(value = "员工id", example = "0")private Integer id;@ApiModelProperty(value = "员工姓名")@NotBlank(message = "员工姓名不能为空")private String name;@ApiModelProperty(value = "员工年龄", example = "0")@NotNull(message = "员工年龄不能为空")private Integer age;
}
dao
层
public interface EmpMapper1 {int deleteByPrimaryKey(Integer id);int insert(Emp record);int insertSelective(Emp record);Emp selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(Emp record);int updateByPrimaryKey(Emp record);
}public interface EmpMapper2 {int deleteByPrimaryKey(Integer id);int insert(Emp record);int insertSelective(Emp record);Emp selectByPrimaryKey(Integer id);int updateByPrimaryKeySelective(Emp record);int updateByPrimaryKey(Emp record);List<Emp> findAll();
}
- 此处不需要
@Mapper
注解,在主从数据源配置类中通过@MapperScan
已经将其分别扫描进Spring
中了
service
层
在 Service
层中根据不同的业务注入不同的 dao
层,这里不再赘述
Controller
层
@Controller
@RequestMapping(path = "/emp")
@Api(tags = "人员管理相关接口")
public class EmpController {@Autowiredprivate EmpService empService;/*** 主数据源test1负责写入数据** @Author: CJ* @Date: 2021-9-2 21:24* @param emp:* @return: org.example.util.ResultMap*/@PostMapping(path = "/addEmp")@ResponseBody@ApiOperation(value = "添加人员的接口")public ResultMap addEmp(@Valid Emp emp, @NotNull BindingResult bindingResult) {if (bindingResult.hasErrors()) {String defaultMessage = Objects.requireNonNull(bindingResult.getFieldError()).getDefaultMessage();return new ResultMap().fail().message(defaultMessage);}int i = empService.addEmp(emp);if (i < 0) {return new ResultMap().fail().message("添加失败");}return new ResultMap().success().message("添加成功");}/*** 从数据源test2负责读取数据** @Author: CJ* @Date: 2021-9-2 21:28* @param id:* @return: org.example.util.ResultMap*/@GetMapping(path = "/findEmp")@ResponseBody@ApiOperation(value = "查询特定人员的接口")@ApiImplicitParam(name = "id", value = "员工id", required = true)public ResultMap findEmp(@RequestParam(name = "id") Integer id) {Emp emp = empService.selectEmpById(id);if (StringUtils.isEmpty(emp)) {return new ResultMap().fail().message("查询失败");}return new ResultMap().success().data(emp).message("查询成功");}/*** 从数据源test2负责读取数据** @Author: CJ* @Date: 2021-9-2 21:28* @return: org.example.util.ResultMap*/@GetMapping("/selectAllEmp")@ResponseBody@ApiOperation(value = "查询所有人员的接口")public ResultMap selectAllEmp() {List<Emp> emps = empService.selectAll();if (CollectionUtils.isEmpty(emps)) {return new ResultMap().fail().message("查询失败");}return new ResultMap().success().data(emps).message("查询成功");}
}
测试
启动 springboot
项目,浏览器中输入:http://localhost:8080/swagger-ui.html
SpringBoot
整合 Swagger
文章:https://blog.csdn.net/weixin_38192427/article/details/120060508
主数据源测试
向主数据源写入数据,参数如下
响应结果如下
主数据库 test1
新增数据如下
使用的数据库连接池是 druid
从数据源测试
test2
从数据库的 emp
表数据
test1
主数据库的 emp
表数据
详细代码参见:https://gitee.com/chaojiangcj/springboot-multipledatasources
SpringBoot配置多数据源(动态切换)相关推荐
- Proxool配置多数据源动态切换
2019独角兽企业重金招聘Python工程师标准>>> 前段时间遇到多数据源动态切换问题,总结一下,做个记录,以备后续之需! 首先附上proxool连接池的配置方法:http://3 ...
- SpringBoot+MybatisPlus多数据源动态切换
公司某项目做大屏展示,但数据来源自7个不同的数据库,需要涉及跨库查询,要求. 本项目采用SpringBoot+MybatisPlus做服务端提供RESTful接口,前后端分离开发,总结一下项目中实现的 ...
- Spring3.3 整合 Hibernate3、MyBatis3.2 配置多数据源/动态切换数据源 方法
原文地址:http://www.cnblogs.com/hoojo/p/Spring_Hibernate_MyBatis_MultipleDataSource_switchDataSource.htm ...
- springboot多数据源动态切换和自定义mybatis分页插件
1.配置多数据源 增加druid依赖 完整pom文件 数据源配置文件 route.datasource.driver-class-name= com.mysql.jdbc.Driver route.d ...
- Spring3 整合MyBatis3 配置多数据源 动态选择SqlSessionFactory
一.摘要 上两篇文章分别介绍了Spring3.3 整合 Hibernate3.MyBatis3.2 配置多数据源/动态切换数据源 方法 和 Spring3 整合Hibernate3.5 动态切换Ses ...
- SpringBoot+AOP实现多数据源动态切换
SpringBoot+AOP实现多数据源动态切换 背景 设计总体思路 步骤 背景 系统后端需要访问多个数据库,现有的数据库连接配置写入配置文件中.后端需要从一个数据库的配置表里动态的读取其它mysql ...
- Spring-Boot + AOP实现多数据源动态切换
2019独角兽企业重金招聘Python工程师标准>>> 最近在做保证金余额查询优化,在项目启动时候需要把余额全量加载到本地缓存,因为需要全量查询所有骑手的保证金余额,为了不影响主数据 ...
- springboot使用mybatis多数据源动态切换的实现
需求:项目使用了读写分离,或者数据进行了分库处理,我们希望在操作不同的数据库的时候,我们的程序能够动态的切换到相应的数据库,执行相关的操作. 首先,你需要一个能够正常运行的springboot项目,配 ...
- Spring+Mybatis多数据源配置(四)——AbstractRoutingDataSource实现数据源动态切换
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...
- springboot配置Druid数据源
springboot配置druid数据源 Author:SimpleWu springboot整合篇 前言 对于数据访问层,无论是Sql还是NoSql,SpringBoot默认采用整合SpringDa ...
最新文章
- nagios视频教程【原创】
- 规律的更新状态是一个好习惯
- Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池
- 目标检测之空间变形网络(STN)
- 黑马安卓74期Android基础(0)
- i219v微星 驱动_MSI微星
- [统计学理论基础] 统计方法—F检验
- 【自用】R语言处理GEO转录组数据记录
- React+Antd+TypeScript 开发规范
- 284、超详细的光纤熔纤、盘纤教程,值得收藏
- 解决error ‘XXX‘ is not defined no-undef且项目没有eslintrc.js文件问题
- linux 命令 root用户把某个文件权限给到普通用户
- ansys_lsdyna输出.k文件lsprepost输出部件加速度
- 杰理之VM 概述【篇】
- 编译librtmp for Android
- PostgreSQL数据库之国际化语言支持学习总结
- STM32F767/429-CAN通信实验
- java对象克隆效率_fastclone
- idea 重新安装流程
- [渝粤教育] 西南科技大学 电工学 在线考试复习资料
热门文章
- 容器技术Docker K8s 33 04-容器服务ACK基础与进阶-06-集群管理
- HDF5 library version mismatched error
- python3 协程_Python3 异步神器-协程(Coroutine)
- 译林 五年级上 单词_译林版小学英语五上Unit 4 HobbiesStory time公开课优质课件教案视频教案...
- Boost组件lexical_cast
- python列表删除会出现一个错误 list index out of range
- vue 背景弹出禁止滚动_vue-蒙层弹窗里的内容滚动。外层大页面禁止滚动
- Mysql更换版本的操作,非常详细(包括数据备份,卸载,安装,还原)
- matlab解六元一次方程,如何用MATLAB编写六元一次方程组
- linux服务之FTP服务篇