springboot2.0动态多数据源切换
摘要:springboot1.x到springboot2.0配置变化有一点变化,网上关于springboot2.0配置多数据源的资料也比较少,为了让大家配置多数据源从springboot1.x升级到springboot2.0少踩写坑,博主在此介绍用springboot2.0来进行动态数据源切换。(在博客的最后会给大家提供源码的下载地址)
一、引入依赖
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.heshouyou</groupId>
- <artifactId>dynamic-datasource</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>dynamic-datasource</name>
- <description>dynamic-datasource project for Spring Boot</description>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.0.0.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-aop</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>1.3.2</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <scope>runtime</scope>
- </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>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-jdbc</artifactId>
- </dependency>
- <dependency>
- <groupId>log4j</groupId>
- <artifactId>log4j</artifactId>
- <version>1.2.17</version>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
- </project>
二、编辑application.yml
- server.port=8080
- #数据源配置(默认)
- #useSSL=false MySQL在高版本需要指明是否进行SSL连接(不加第一次连接数据库会有警告信息)
- spring.datasource.driver=com.mysql.jdbc.Driver
- spring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false
- spring.datasource.username=root
- spring.datasource.password=123456
- #ds1,ds2 其他两个数据源
- slave.datasource.names=ds1,ds2
- #ds1
- slave.datasource.ds1.driver=com.mysql.jdbc.Driver
- slave.datasource.ds1.url=jdbc:mysql://localhost:3306/test1?useSSL=false
- slave.datasource.ds1.username=root
- slave.datasource.ds1.password=123456
- #ds2
- slave.datasource.ds2.driver=com.mysql.jdbc.Driver
- slave.datasource.ds2.url=jdbc:mysql://localhost:3306/test2?useSSL=false
- slave.datasource.ds2.username=root
- slave.datasource.ds2.password=123456
- #mapper.xml文件
- mybatis.mapper-locations=classpath:mapper/*.xml
- #实体类包
- mybatis.type-aliases-package=datasource.springboot_datasource.entity
三、DataSource工具类
动态切换类
- package com.chaoqi.springboot_datasource.config;
- import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
- /**
- * @Author caiChaoqi
- * @Date 2018-06-23
- * @Description 动态数据源
- * AbstractRoutingDataSource(每执行一次数据库,动态获取DataSource)
- */
- public class DynamicDataSource extends AbstractRoutingDataSource {
- @Override
- protected Object determineCurrentLookupKey() {
- return DynamicDataSourceContextHolder.getDataSourceType();
- }
- }
- 动态数据源上下文管理
- package com.chaoqi.springboot_datasource.config;
- import org.apache.log4j.Logger;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @Author caiChaoqi
- * @Date 2018-06-23
- * @Description 动态数据源上下文管理
- */
- public class DynamicDataSourceContextHolder {
- private Logger logger = Logger.getLogger(DynamicDataSourceContextHolder.class);
- //存放当前线程使用的数据源类型信息
- private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
- //存放数据源id
- public static List<String> dataSourceIds = new ArrayList<String>();
- //设置数据源
- public static void setDataSourceType(String dataSourceType) {
- contextHolder.set(dataSourceType);
- }
- //获取数据源
- public static String getDataSourceType() {
- return contextHolder.get();
- }
- //清除数据源
- public static void clearDataSourceType() {
- contextHolder.remove();
- }
- //判断当前数据源是否存在
- public static boolean isContainsDataSource(String dataSourceId) {
- return dataSourceIds.contains(dataSourceId);
- }
- }
- 初始化数据源和提供了执行动态切换数据源的工具类
- package com.chaoqi.springboot_datasource.config;
- import org.apache.log4j.Logger;
- import org.springframework.beans.MutablePropertyValues;
- import org.springframework.beans.factory.support.BeanDefinitionRegistry;
- import org.springframework.beans.factory.support.GenericBeanDefinition;
- import org.springframework.boot.jdbc.DataSourceBuilder;
- import org.springframework.context.EnvironmentAware;
- import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
- import org.springframework.core.env.Environment;
- import org.springframework.core.type.AnnotationMetadata;
- import javax.sql.DataSource;
- import java.util.HashMap;
- import java.util.Map;
- /**
- * @Author caiChaoqi
- * @Date 2018-06-23
- * @Description 注册动态数据源
- * 初始化数据源和提供了执行动态切换数据源的工具类
- * EnvironmentAware(获取配置文件配置的属性值)
- */
- public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
- private Logger logger = Logger.getLogger(DynamicDataSourceRegister.class);
- //指定默认数据源(springboot2.0默认数据源是hikari如何想使用其他数据源可以自己配置)
- private static final String DATASOURCE_TYPE_DEFAULT = "com.zaxxer.hikari.HikariDataSource";
- //默认数据源
- private DataSource defaultDataSource;
- //用户自定义数据源
- private Map<String, DataSource> slaveDataSources = new HashMap<>();
- @Override
- public void setEnvironment(Environment environment) {
- initDefaultDataSource(environment);
- initslaveDataSources(environment);
- }
- private void initDefaultDataSource(Environment env) {
- // 读取主数据源
- Map<String, Object> dsMap = new HashMap<>();
- dsMap.put("driver", env.getProperty("spring.datasource.driver"));
- dsMap.put("url", env.getProperty("spring.datasource.url"));
- dsMap.put("username", env.getProperty("spring.datasource.username"));
- dsMap.put("password", env.getProperty("spring.datasource.password"));
- defaultDataSource = buildDataSource(dsMap);
- }
- private void initslaveDataSources(Environment env) {
- // 读取配置文件获取更多数据源
- String dsPrefixs = env.getProperty("slave.datasource.names");
- for (String dsPrefix : dsPrefixs.split(",")) {
- // 多个数据源
- Map<String, Object> dsMap = new HashMap<>();
- dsMap.put("driver", env.getProperty("slave.datasource." + dsPrefix + ".driver"));
- dsMap.put("url", env.getProperty("slave.datasource." + dsPrefix + ".url"));
- dsMap.put("username", env.getProperty("slave.datasource." + dsPrefix + ".username"));
- dsMap.put("password", env.getProperty("slave.datasource." + dsPrefix + ".password"));
- DataSource ds = buildDataSource(dsMap);
- slaveDataSources.put(dsPrefix, ds);
- }
- }
- @Override
- public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
- Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
- //添加默认数据源
- targetDataSources.put("dataSource", this.defaultDataSource);
- DynamicDataSourceContextHolder.dataSourceIds.add("dataSource");
- //添加其他数据源
- targetDataSources.putAll(slaveDataSources);
- for (String key : slaveDataSources.keySet()) {
- DynamicDataSourceContextHolder.dataSourceIds.add(key);
- }
- //创建DynamicDataSource
- GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
- beanDefinition.setBeanClass(DynamicDataSource.class);
- beanDefinition.setSynthetic(true);
- MutablePropertyValues mpv = beanDefinition.getPropertyValues();
- mpv.addPropertyValue("defaultTargetDataSource", defaultDataSource);
- mpv.addPropertyValue("targetDataSources", targetDataSources);
- //注册 - BeanDefinitionRegistry
- beanDefinitionRegistry.registerBeanDefinition("dataSource", beanDefinition);
- logger.info("Dynamic DataSource Registry");
- }
- public DataSource buildDataSource(Map<String, Object> dataSourceMap) {
- try {
- Object type = dataSourceMap.get("type");
- if (type == null) {
- type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
- }
- Class<? extends DataSource> dataSourceType;
- dataSourceType = (Class<? extends DataSource>) Class.forName((String) type);
- String driverClassName = dataSourceMap.get("driver").toString();
- String url = dataSourceMap.get("url").toString();
- String username = dataSourceMap.get("username").toString();
- String password = dataSourceMap.get("password").toString();
- // 自定义DataSource配置
- DataSourceBuilder factory = DataSourceBuilder.create().driverClassName(driverClassName).url(url)
- .username(username).password(password).type(dataSourceType);
- return factory.build();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return null;
- }
- }
自定义注解
- package com.chaoqi.springboot_datasource.config;
- import java.lang.annotation.*;
- /**
- * @Author caiChaoqi
- * @Date 2018-06-23
- * @Description 作用于类、接口或者方法上
- */
- @Target({ElementType.TYPE, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @Documented
- public @interface TargetDataSource {
- String name();
- }
- 动态数据源通知
- package com.chaoqi.springboot_datasource.config;
- import org.apache.log4j.Logger;
- import org.aspectj.lang.JoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.springframework.core.annotation.Order;
- import org.springframework.stereotype.Component;
- /**
- * @Author caiChaoqi
- * @Description 动态数据源通知
- * @Date 2018-06-23
- */
- @Aspect
- @Order(-1)//保证在@Transactional之前执行
- @Component
- public class DynamicDattaSourceAspect {
- private Logger logger = Logger.getLogger(DynamicDattaSourceAspect.class);
- //改变数据源
- @Before("@annotation(targetDataSource)")
- public void changeDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
- String dbid = targetDataSource.name();
- if (!DynamicDataSourceContextHolder.isContainsDataSource(dbid)) {
- //joinPoint.getSignature() :获取连接点的方法签名对象
- logger.error("数据源 " + dbid + " 不存在使用默认的数据源 -> " + joinPoint.getSignature());
- } else {
- logger.debug("使用数据源:" + dbid);
- DynamicDataSourceContextHolder.setDataSourceType(dbid);
- }
- }
- @After("@annotation(targetDataSource)")
- public void clearDataSource(JoinPoint joinPoint, TargetDataSource targetDataSource) {
- logger.debug("清除数据源 " + targetDataSource.name() + " !");
- DynamicDataSourceContextHolder.clearDataSourceType();
- }
- }
核心代码以全部展示,源码下载地址:https://github.com/caicahoqi/ChaoqiIsPrivateLibrary 如果在项目搭建中遇到问题可以在评论区留言,博主看到第一时间会给予回复,谢谢
springboot2.0动态多数据源切换的更多相关文章
- springboot2.0+mybatis多数据源集成
最近在学springboot,把学的记录下来.主要有springboot2.0+mybatis多数据源集成,logback日志集成,springboot单元测试. 一.代码结构如下 二.pom.xml ...
- SpringBoot与动态多数据源切换
本文简单的介绍一下基于SpringBoot框架动态多数据源切换的实现,采用主从配置的方式,配置master.slave两个数据库. 一.配置主从数据库 spring: datasource: ty ...
- springboot(2.0以上) --数据源切换时报错
在进行数据源切换时spring.datasource.type类型根据源码所给的默认值修改后依然报错 先看源码:标色部分 , 就是springboot所给的数据源 , 正常来说只要在配置文件中修改 ...
- springboot动态多数据源切换
application-test.properties #datasource -- mysql multiple.datasource.master.url=jdbc:mysql://localho ...
- springboot学习入门简易版九---springboot2.0整合多数据源mybatis mysql8+(22)
一个项目中配置多个数据源(链接不同库jdbc),无限大,具体多少根据内存大小 项目中多数据源如何划分:分包名(业务)或注解方式.分包名方式类似多个不同的jar,同业务需求放一个包中. 分包方式配置多数 ...
- SpringBoot2.0之八 多数据源配置
在开发的过程中我们可能都会遇到对接公司其他系统等需求,对于外部的系统可以采用接口对接的方式,对于一个公司开发的两个系统,并且知道相关数据库结构的情况下,就可以考虑使用多数据源来解决这个问题.Spri ...
- SpringBoot2.0 配置多数据源
一.简述 配置多数据源意思就是在一个项目中使用多个数据库,在项目使用中可以不用手动切换数据库来实现不同数据库的数据获取和更新. 源码地址: https://github.com/hanguilin/b ...
- SpringBoot2 + Druid + Mybatis 多数据源动态配置
在大数据高并发的应用场景下,为了更快的响应用户请求,读写分离是比较常见的应对方案.读写分离会使用多数据源的使用.下面记录如何搭建SpringBoot2 + Druid + Mybatis 多数据源配 ...
- Spring(AbstractRoutingDataSource)实现动态数据源切换--转载
原始出处:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目 ...
随机推荐
- day34-python操作redis三
Hash类型操作 Hash类型操作 Redis在内存中存储hash类型是以name对应一个字典形式存储的 hset(name,key,value) #name对应的hash中设置一个键值对(不存在,则 ...
- EasyExcel导入工具(SpringMVC下使用)
easyExcel:由阿里巴巴公司开发,由github托管 github上有详细使用文档 github地址:https://github.com/alibaba/easyexcel/blob/mast ...
- L1-058 6翻了
“666”是一种网络用语,大概是表示某人很厉害.我们很佩服的意思.最近又衍生出另一个数字“9”,意思是“6翻了”,实在太厉害的意思.如果你以为这就是厉害的最高境界,那就错啦 —— 目前的最高境界是数字 ...
- 世界上最好的Sed教程
这是一份世界上最好的sed教程,sed是unix系统下流编辑里的超人.最初我写这份说明是为了我的 第二本电子书,然而随后我决定把这份说明变成一本免费电子书预览的同时再次做为文章发布到这里. Sed说明 ...
- 学号 20175223 《Java程序设计》第2周学习总结
学号 20175223 <Java程序设计>第2周学习总结 教材学习内容总结 第二章要点: 要点1:标识符与关键字 要点2:基本数据类型:逻辑类型boolean,整数类型int|byte| ...
- HTML5:图片、音乐和视频
图片.音乐和视频 一.图片 1.属性 属性 说明 alt 规定图像的替代文本. src 规定显示图像的 URL align 规定如何根据周围的文本来排列图像. border 定义图像周围的边框. he ...
- find: paths must precede expression问题及解决
用find命令查找时 例如命令 会出错,查文档找出 find: paths must precede expression Usage: find [-H] [-L] [-P] [-Olevel] [ ...
- 基于Verilog的带FIFO写入缓冲的串口发送接口封装
一.模块框图及基本思路 tx_module:串口发送的核心模块,详细介绍请参照前面的“基于Verilog的串口发送实验” fifo2tx_module:当fifo不为空时,读取fifo中的数据并使能发 ...
- 阿里的maven镜像仓库,eclipse中使用maven下载jar包的时候提升速度
<mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> & ...
- openssl查看apk的证书信息
查看apk的证书信息: openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text