Spring boot 整合dynamic实现多数据源
时间:2022-07-22
本文章向大家介绍Spring boot 整合dynamic实现多数据源,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
项目git地址:git
准备工作
# 创建数据库db1
CREATE DATABASE `db1`CHARACTER SET utf8 COLLATE utf8_bin
# 创建user表
CREATE TABLE `user` (
`id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
# 添加数据
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (1, 'db1_1');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (2, 'db1_2');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (3, 'db1_3');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (4, 'db1_4');
INSERT INTO `db1`.`user` (`id`, `name`) VALUES (5, 'db1_5');
# 创建数据库db2
CREATE DATABASE `db2`CHARACTER SET utf8 COLLATE utf8_bin
# 创建user表
CREATE TABLE `user` (
`id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8
# 添加数据
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (1, 'db2_1');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (2, 'db2_2');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (3, 'db2_3');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (4, 'db2_4');
INSERT INTO `db2`.`user` (`id`, `name`) VALUES (5, 'db2_5');
创建项目
最终目录结果
添加依赖
<!-- mysql start -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mysql end -->
<!-- web start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- web end -->
<!-- lombok start -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- lombok end -->
<!-- hutool start -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.versiont}</version>
</dependency>
<!-- hutool end -->
<!-- configuration start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- configuration end -->
<!-- swagger start -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<!-- swagger end -->
<!-- mybatis-plus start -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.0</version>
</dependency>
<!-- mybatis-plus end -->
<!-- spring aop start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- spring aop end -->
添加配置
server:
port: 8085
spring:
datasource:
db1:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
hikari:
maximum-pool-size: 20
minimum-idle: 2
url: jdbc:mysql://localhost:3306/springbootdb?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
db2:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
hikari:
maximum-pool-size: 20
minimum-idle: 2
url: jdbc:mysql://localhost:3306/springbootdb2?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai
定义枚举
package cn.org.jacob.enums;
//...
public enum DataSourceTypeEnum {
DB1,
DB2
}
编写aop
package cn.org.jacob.aop;
//...
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DataSource {
DataSourceTypeEnum value() default DataSourceTypeEnum.DB1;
}
package cn.org.jacob.aop;
//...
@Slf4j
@Aspect
@Component
@Order(-1)
public class DataSourceAspect {
@Pointcut("@annotation(cn.org.jacob.aop.DataSource)")
public void dataSourceAspectMethod() {
}
@Before(value = "dataSourceAspectMethod()")
public void beforeDataSource(JoinPoint joinPoint) {
// log.info("进入切点>>>>>>>>>>>>>>>>>>>>>>>>>>>执行切换数据源");
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
DataSource annotation = signature.getMethod().getAnnotation(DataSource.class);
DataSourceTypeEnum value = annotation.value();
DataSourceContextHolder.setDataSource(value);
log.info("当前使用的数据源:{}", value);
}
@After("dataSourceAspectMethod()")
public void afterDataSource() {
DataSourceContextHolder.clear();
}
}
package cn.org.jacob.aop;
//...
public class DataSourceContextHolder {
/**
* 吧数据源存放当前线程
*/
private static final ThreadLocal<DataSourceTypeEnum> contextHolder = new ThreadLocal<>();
/**
* 设置数据源
*
* @param dataSource 当前的数据源
*/
public static void setDataSource(DataSourceTypeEnum dataSource) {
contextHolder.set(dataSource);
}
/**
* 获取数据源
*
* @return 当前数据源
*/
public static DataSourceTypeEnum getDataSource() {
return contextHolder.get();
}
/**
* 删除当前线程上下文的数据源信息
*/
public static void clear() {
contextHolder.remove();
}
}
编写配置
package cn.org.jacob.config;
//..
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("cn.org.jacob"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("swagger-bootstrap-ui RESTful APIs")
.description("swagger-bootstrap-ui")
.termsOfServiceUrl("http://localhost:8081/")
.contact("m15870979735@163.com")
.version("1.0")
.build();
}
}
package cn.org.jacob.config;
//..
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.db1")
public class Db1Config {
private String driverClassName;
private String userName;
private String password;
private String url;
}
package cn.org.jacob.config;
//..
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.db2")
public class Db2Config {
private String driverClassName;
private String userName;
private String password;
private String url;
}
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
package cn.org.jacob.config;
//..
@Configuration
@MapperScan("cn.org.jacob.mapper")
@Slf4j
public class MybatisPlusConfigurer {
@Autowired
Db1Config db1Config;
@Autowired
Db2Config db2Config;
/**
* 分页插件
*
* @return PaginationInterceptor
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
@Primary
@Bean(value = "db1DataSource")
public DataSource roadDataSource() {
return DataSourceBuilder.create().url(db1Config.getUrl())
.driverClassName(db1Config.getDriverClassName()).username(db1Config.getUserName())
.password(db1Config.getPassword()).type(HikariDataSource.class).build();
}
@Bean(value = "db2DataSource")
public DataSource garageDataSource() {
return DataSourceBuilder.create().url(db2Config.getUrl())
.driverClassName(db2Config.getDriverClassName()).username(db2Config.getUserName())
.password(db2Config.getPassword()).type(HikariDataSource.class).build();
}
@Bean
public DynamicDataSource dataSource(@Qualifier("db1DataSource") DataSource db1DataSource,
@Qualifier("db2DataSource") DataSource db2DataSource) {
Map<Object, Object> map = new HashMap<>(2);
map.put(DataSourceTypeEnum.DB1, db1DataSource);
map.put(DataSourceTypeEnum.DB2, db2DataSource);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setTargetDataSources(map);
dynamicDataSource.setDefaultTargetDataSource(db1DataSource);
return dynamicDataSource;
}
@Bean
public MybatisSqlSessionFactoryBean sqlSessionFactoryBean() throws Exception {
MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
// 重新设置数据源 DB1,DB2 两个
sqlSessionFactoryBean.setDataSource(dataSource(roadDataSource(), garageDataSource()));
Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml");
sqlSessionFactoryBean.setMapperLocations(resources);
// 手动设置分页插件
sqlSessionFactoryBean.setPlugins(new Interceptor[] { paginationInterceptor() });
return sqlSessionFactoryBean;
}
@Bean
public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
}
实体类,Mapper,service忽略
编写控制器
@RestController
@Slf4j
@Api(value = "用户", tags = {"用户"})
@AllArgsConstructor
@RequestMapping("user")
public class UserController {
private UserService userService;
@GetMapping("db1List")
@ApiOperation(value = "获取db1List")
@DataSource(DataSourceTypeEnum.DB1)
public List<User> db1List(){
return userService.list();
}
@GetMapping("db2List")
@ApiOperation(value = "获取db2List")
@DataSource(DataSourceTypeEnum.DB2)
public List<User> db2List(){
return userService.list();
}
}
访问查看效果
- 如何用<dl>标签做表格而不用table标签
- Gulp使用指南
- Gulp Error: Cannot find module 'jshint/src/cli'
- 自学如何使用Python和Keras构建你自己专属的AlphaZero系统
- 用Visual Studio Code写Node.j
- 帝国CMS搜索页伪静态实现方法
- 5步搭建GO环境
- 你真的了解如何将 Nginx 配置为Web服务器吗
- 12个JavaScript技巧
- 梯度是如何计算的
- Java 机器学习库Smile实战(二)AdaBoost
- 如何用excel urldecode解码把url编码转为汉字?
- Scikit-learn实战之 SVM回归分析、密度估计、异常点检测
- TensorFlow模拟简单线性模型小栗子
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 团体程序设计天梯赛-练习集 L1-007 念数字
- 团体程序设计天梯赛-练习集 L1-008 求整数段和
- K8s多租户场景下的多层级namespace规则解析
- 团体程序设计天梯赛-练习集 L1-010 比较大小
- 团体程序设计天梯赛-练习集 L1-012 计算指数
- 团体程序设计天梯赛-练习集 L1-013 计算阶乘和
- 团体程序设计天梯赛-练习集 L1-036 A乘以B
- 团体程序设计天梯赛-练习集 L1-015 跟奥巴马一起画方块
- 团体程序设计天梯赛-练习集 L1-011 A-B
- vuepress引入vue-qr组件后build报错navigator is not defined问题
- 团体程序设计天梯赛-练习集 L1-022 奇偶分家
- k8s——针对有状态服务实现数据持久化
- 团体程序设计天梯赛-练习集 L1-017 到底有多二
- 团体程序设计天梯赛-练习集 L1-032 Left-pad
- ansible运行报错CryptographyDeprecationWarning解决