公司某项目做大屏展示,但数据来源自7个不同的数据库,需要涉及跨库查询,要求。

本项目采用SpringBoot+MybatisPlus做服务端提供RESTful接口,前后端分离开发,总结一下项目中实现的动态数据源切换的实现方式。

首先在application文件中配置数据源

spring:aop:proxy-target-class: trueauto: truedatasource:druid:# 一期数据源db1:url: jdbc:oracle:thin:@172.16.3.131:1521:orclusername: ZHJGDSJpassword: ZHJGDSJdriver-class-name: oracle.jdbc.driver.OracleDriverinitialSize: 5minIdle: 5maxActive: 20# 二期 诚信监管db2:url: jdbc:oracle:thin:@172.17.2.119:1521:orclusername: cxjg_test1password: 123456driver-class-name: oracle.jdbc.driver.OracleDriverinitialSize: 5minIdle: 5maxActive: 20# 二期 协同监管db3:url: jdbc:oracle:thin:@172.17.2.119:1521:orclusername: xtjg_testpassword: 123456driver-class-name: oracle.jdbc.driver.OracleDriverinitialSize: 5minIdle: 5maxActive: 20# 二期 公示系统db4:url: jdbc:oracle:thin:@172.17.2.119:1521:orclusername: GSGSpassword: 123456driver-class-name: oracle.jdbc.driver.OracleDriverinitialSize: 5minIdle: 5maxActive: 20# 二期 省局-浪潮库db5:url: jdbc:oracle:thin:@172.16.1.26:1521:orclusername: GSYWpassword: 123456driver-class-name: oracle.jdbc.driver.OracleDriverinitialSize: 5minIdle: 5maxActive: 20# 二期 市局-浪潮库db6:url: jdbc:oracle:thin:@172.16.1.65:1521:orclusername: GSYWSJpassword: 123456driver-class-name: oracle.jdbc.driver.OracleDriverinitialSize: 5minIdle: 5maxActive: 20# 二期 正元db7:url: jdbc:oracle:thin:@172.17.2.119:1521:orclusername: ZHJGDSJpassword: 123456driver-class-name: oracle.jdbc.driver.OracleDriverinitialSize: 5minIdle: 5maxActive: 20

创建一个数据源枚举类

package com.rexen.di.management.common.type;/*** @Author Jimmy* @date 2019/2/7.*/
public enum DBTypeEnum {db1("db1"), db2("db2"), db3("db3"), db4("db4"), db5("db5"), db6("db6"), db7("db7");private String value;DBTypeEnum(String value) {this.value = value;}public String getValue() {return value;}
}

创建一个上下文来缓存当前数据源

package com.rexen.di.management.boot.config;import com.rexen.di.management.common.type.DBTypeEnum;/*** @Author Jimmy* @date 2019/2/7.*/
public class DbContextHolder {private static final ThreadLocal contextHolder = new ThreadLocal<>();/*** 设置数据源* @param dbTypeEnum*/public static void setDbType(DBTypeEnum dbTypeEnum) {contextHolder.set(dbTypeEnum.getValue());}/*** 取得当前数据源* @return*/public static String getDbType() {return (String) contextHolder.get();}/*** 清除上下文数据*/public static void clearDbType() {contextHolder.remove();}
}

创建AbstractRoutingDataSource 的实现类实现切换

package com.rexen.di.management.boot.config;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** @Author Jimmy* @date 2019/2/7.*/
public class DynamicDataSource extends AbstractRoutingDataSource {/*** 取得当前使用哪个数据源* @return*/@Overrideprotected Object determineCurrentLookupKey() {return DbContextHolder.getDbType();}
}

通过AOP方式实现拦截和切换,根据Mapper路径来决定切换到哪个数据源

package com.rexen.di.management.boot.advice;import com.rexen.di.management.boot.config.DbContextHolder;
import com.rexen.di.management.common.annotation.DataSourceSwitch;
import com.rexen.di.management.common.type.DBTypeEnum;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.util.Objects;/*** @Author Jimmy* @date 2019/2/7.*/@Component
@Aspect
@Order(-100)
public class DataSourceSwitchAspect {Logger log = Logger.getLogger(DataSourceSwitchAspect.class);@Pointcut("execution(* com.rexen.di.management.mapper..*.*(..))")private void db1Aspect() {}@Pointcut("execution(* com.rexen.di.management.custom2.mapper..*.*(..))")private void db2Aspect() {}@Pointcut("execution(* com.rexen.di.management.custom3.mapper..*.*(..))")private void db3Aspect() {}@Pointcut("execution(* com.rexen.di.management.custom4.mapper..*.*(..))")private void db4Aspect() {}@Pointcut("execution(* com.rexen.di.management.custom5.mapper..*.*(..))")private void db5Aspect() {}@Pointcut("execution(* com.rexen.di.management.custom6.mapper..*.*(..))")private void db6Aspect() {}@Pointcut("execution(* com.rexen.di.management.custom7.mapper..*.*(..))")private void db7Aspect() {}@Before( "db1Aspect()" )public void db1(JoinPoint joinPoint) {log.info("切换到db1 数据源...");setDataSource(joinPoint, DBTypeEnum.db1);}@Before("db2Aspect()" )public void db2 (JoinPoint joinPoint) {log.info("切换到db2 数据源...");setDataSource(joinPoint,DBTypeEnum.db2);}@Before("db3Aspect()" )public void db3 (JoinPoint joinPoint) {log.info("切换到db3 数据源...");setDataSource(joinPoint,DBTypeEnum.db3);}@Before("db4Aspect()" )public void db4 (JoinPoint joinPoint) {log.info("切换到db4 数据源...");setDataSource(joinPoint,DBTypeEnum.db4);}@Before("db5Aspect()" )public void db5 (JoinPoint joinPoint) {log.info("切换到db5 数据源...");setDataSource(joinPoint,DBTypeEnum.db5);}@Before("db6Aspect()" )public void db6 (JoinPoint joinPoint) {log.info("切换到db6 数据源...");setDataSource(joinPoint,DBTypeEnum.db6);}@Before("db7Aspect()" )public void db7 (JoinPoint joinPoint) {log.info("切换到db7 数据源...");setDataSource(joinPoint,DBTypeEnum.db7);}/*** 添加注解方式,如果有注解优先注解,没有则按传过来的数据源配置* @param joinPoint* @param dbTypeEnum*/private void setDataSource(JoinPoint joinPoint, DBTypeEnum dbTypeEnum) {MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();DataSourceSwitch dataSourceSwitch = methodSignature.getMethod().getAnnotation(DataSourceSwitch.class);if (Objects.isNull(dataSourceSwitch) || Objects.isNull(dataSourceSwitch.value())) {DbContextHolder.setDbType(dbTypeEnum);}else{log.info("根据注解来切换数据源,注解值为:"+dataSourceSwitch.value());switch (dataSourceSwitch.value().getValue()) {case "db1":DbContextHolder.setDbType(DBTypeEnum.db1);break;case "db2":DbContextHolder.setDbType(DBTypeEnum.db2);break;case "db3":DbContextHolder.setDbType(DBTypeEnum.db3);break;case "db4":DbContextHolder.setDbType(DBTypeEnum.db4);break;case "db5":DbContextHolder.setDbType(DBTypeEnum.db5);break;case "db6":DbContextHolder.setDbType(DBTypeEnum.db6);break;case "db7":DbContextHolder.setDbType(DBTypeEnum.db7);break;default:DbContextHolder.setDbType(dbTypeEnum);}}}
}

创建MybatisPlus的配置文件

package com.rexen.di.management.boot.config;import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.MybatisConfiguration;
import com.baomidou.mybatisplus.entity.GlobalConfiguration;
import com.baomidou.mybatisplus.mapper.LogicSqlInjector;
import com.baomidou.mybatisplus.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean;
import com.rexen.di.management.common.type.DBTypeEnum;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** @Author Jimmy* @date 2019/2/6.*/
@Configuration
@MapperScan({"com.rexen.di.management.mapper","com.rexen.di.management.custom2.mapper","com.rexen.di.management.custom3.mapper","com.rexen.di.management.custom4.mapper","com.rexen.di.management.custom5.mapper","com.rexen.di.management.custom6.mapper","com.rexen.di.management.custom7.mapper"})
public class MybatisPlusConfig {/*** mybatis-plus分页插件<br>* 文档:http://mp.baomidou.com<br>*/@Beanpublic PaginationInterceptor paginationInterceptor() {PaginationInterceptor paginationInterceptor = new PaginationInterceptor();//paginationInterceptor.setLocalPage(true);// 开启 PageHelper 的支持return paginationInterceptor;}/*** mybatis-plus SQL执行效率插件【生产环境可以关闭】*/@Beanpublic PerformanceInterceptor performanceInterceptor() {return new PerformanceInterceptor();}@Bean(name = "db1")@ConfigurationProperties(prefix = "spring.datasource.druid.db1" )public DataSource db1 () {return DruidDataSourceBuilder.create().build();}@Bean(name = "db2")@ConfigurationProperties(prefix = "spring.datasource.druid.db2" )public DataSource db2 () {return DruidDataSourceBuilder.create().build();}@Bean(name = "db3")@ConfigurationProperties(prefix = "spring.datasource.druid.db3" )public DataSource db3 () {return DruidDataSourceBuilder.create().build();}@Bean(name = "db4")@ConfigurationProperties(prefix = "spring.datasource.druid.db4" )public DataSource db4 () {return DruidDataSourceBuilder.create().build();}@Bean(name = "db5")@ConfigurationProperties(prefix = "spring.datasource.druid.db5" )public DataSource db5 () {return DruidDataSourceBuilder.create().build();}@Bean(name = "db6")@ConfigurationProperties(prefix = "spring.datasource.druid.db6" )public DataSource db6 () {return DruidDataSourceBuilder.create().build();}@Bean(name = "db7")@ConfigurationProperties(prefix = "spring.datasource.druid.db7" )public DataSource db7 () {return DruidDataSourceBuilder.create().build();}/*** 动态数据源配置* @return*/@Bean@Primarypublic DataSource multipleDataSource (@Qualifier("db1") DataSource db1,@Qualifier("db2") DataSource db2,@Qualifier("db3") DataSource db3,@Qualifier("db4") DataSource db4,@Qualifier("db5") DataSource db5,@Qualifier("db6") DataSource db6,@Qualifier("db7") DataSource db7) {DynamicDataSource dynamicDataSource = new DynamicDataSource();Map< Object, Object > targetDataSources = new HashMap<>();targetDataSources.put(DBTypeEnum.db1.getValue(), db1 );targetDataSources.put(DBTypeEnum.db2.getValue(), db2);targetDataSources.put(DBTypeEnum.db3.getValue(), db3);targetDataSources.put(DBTypeEnum.db4.getValue(), db4);targetDataSources.put(DBTypeEnum.db5.getValue(), db5);targetDataSources.put(DBTypeEnum.db6.getValue(), db6);targetDataSources.put(DBTypeEnum.db7.getValue(), db7);dynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.setDefaultTargetDataSource(db1);return dynamicDataSource;}@Bean("sqlSessionFactory")public SqlSessionFactory sqlSessionFactory() throws Exception {MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();sqlSessionFactory.setDataSource(multipleDataSource(db1(),db2(),db3(),db4(),db5(),db6(),db7()));sqlSessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/**/*Mapper.xml"));MybatisConfiguration configuration = new MybatisConfiguration();//configuration.setDefaultScriptingLanguage(MybatisXMLLanguageDriver.class);configuration.setJdbcTypeForNull(JdbcType.NULL);configuration.setMapUnderscoreToCamelCase(true);configuration.setCacheEnabled(false);sqlSessionFactory.setConfiguration(configuration);sqlSessionFactory.setPlugins(new Interceptor[]{ //PerformanceInterceptor(),OptimisticLockerInterceptor()paginationInterceptor()});sqlSessionFactory.setGlobalConfig(globalConfiguration());return sqlSessionFactory.getObject();}@Beanpublic GlobalConfiguration globalConfiguration() {GlobalConfiguration conf = new GlobalConfiguration(new LogicSqlInjector());conf.setLogicDeleteValue("-1");conf.setLogicNotDeleteValue("1");conf.setIdType(0);conf.setMetaObjectHandler(new MyMetaObjectHandler());conf.setDbColumnUnderline(true);conf.setRefresh(true);return conf;}}

SpringBoot+MybatisPlus多数据源动态切换相关推荐

  1. springboot多数据源动态切换和自定义mybatis分页插件

    1.配置多数据源 增加druid依赖 完整pom文件 数据源配置文件 route.datasource.driver-class-name= com.mysql.jdbc.Driver route.d ...

  2. SpringBoot+AOP实现多数据源动态切换

    SpringBoot+AOP实现多数据源动态切换 背景 设计总体思路 步骤 背景 系统后端需要访问多个数据库,现有的数据库连接配置写入配置文件中.后端需要从一个数据库的配置表里动态的读取其它mysql ...

  3. Spring-Boot + AOP实现多数据源动态切换

    2019独角兽企业重金招聘Python工程师标准>>> 最近在做保证金余额查询优化,在项目启动时候需要把余额全量加载到本地缓存,因为需要全量查询所有骑手的保证金余额,为了不影响主数据 ...

  4. springboot使用mybatis多数据源动态切换的实现

    需求:项目使用了读写分离,或者数据进行了分库处理,我们希望在操作不同的数据库的时候,我们的程序能够动态的切换到相应的数据库,执行相关的操作. 首先,你需要一个能够正常运行的springboot项目,配 ...

  5. Proxool配置多数据源动态切换

    2019独角兽企业重金招聘Python工程师标准>>> 前段时间遇到多数据源动态切换问题,总结一下,做个记录,以备后续之需! 首先附上proxool连接池的配置方法:http://3 ...

  6. Spring+Mybatis多数据源配置(四)——AbstractRoutingDataSource实现数据源动态切换

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  7. springboot多数据源动态切换,事务下切换数据源(非分布式事务)

    目录 1.业务场景 2.主要思路 3.加载默认数据源 4.多数据源规则配置 5.程序启动加载子公司数据源 6.自定义事务注解 7.程序中调用 1.业务场景 因为业务业务需求,需要把基础数据与子公司业务 ...

  8. springboot mybatisplus 多数据源_【SpringBoot DB 系列】MybatisPlus 多数据源配置

    [SpringBoot DB 系列]Mybatis-Plus 多数据源配置 前面介绍了两种 Mybatis 的数据源配置,当然也少不了 mybatis-plus MyBatis-Plus (opens ...

  9. 手把手教你玩多数据源动态切换

    为了提高应用的可靠性,多数据源现在也很常见,数据库可以搭建双 M 结构,这个松哥之前也发文和大家分享过如何搭建双 M 结构的主从备份?,那么 Java 代码里该如何操作多数据源呢? 我在 19 年的时 ...

最新文章

  1. 《研磨设计模式》chap18 状态模式state(1)模式简介
  2. 在Spring Boot中使用配置元数据来配置您的配置
  3. ubuntu下搭建nfs服务器
  4. 云之讯api接口php,1. 接口对接
  5. 安卓固件修改工具_【固件升级】给力!安卓6.0以上设备均已升级BOOX OS 2.3系统...
  6. Qt:QListWidget的item上实现右键菜单
  7. Android通过命令连接wifi(解决usb不能用+无屏幕情况)
  8. mysql的replication(主从同步)总结
  9. txt文件转为excel文件
  10. blender 中文手册 Blender从入门到精通
  11. CI521支持读写A卡和B卡,PIN对PIN直接替换CV520和CI520,软硬件兼容
  12. 微信群发图文消息步骤说明
  13. 微信小程序-批量地图标记
  14. 用循环不定式来证明冒泡排序的正确性
  15. 元祖python_Python-数据类型-元祖
  16. 剑指Offer对答如流系列 - 构建乘积数组
  17. 虹科案例 | 空调故障无冷气,且没有故障码
  18. l1-044. 稳赢c语言,L1-044 稳赢 (15 分)(解析有坑点)
  19. bmi系统模块设计java_BMI体脂计算器 app源码
  20. 天旦发布“数据驱动决策”实践指南,推进数字化转型

热门文章

  1. Linux jq 、vim以及LInux集群安装miniconda并配置虚拟环境(笔记)
  2. 高职计算机考试试题与答案,2009高职高考计算机试题
  3. java自动化测试语言高级之Java 9 新特性
  4. UE4之Spline
  5. (二十五)套利定价理论(APT)
  6. java value是什么意思_“预期 Value ,发现特质”是什么意思?
  7. 让你不再害怕指针——C指针详解(经典,非常详细)
  8. 男主龙失忆java_不容错过的3本男主失忆文:我忘记了以前的所有,却从未忘记爱你...
  9. Caff-Opencv——图像分类(01)
  10. 收单外包机构为何会被强制取消备案