• Springboot-配置多数据源-接口切换


    Application添加注解: @Import({DynamicDataSourceRegister.class}) 

    application.xml配置从数据源:

    slave:
        datasource:
            names: name1 ,name2
            name1:
                driver-class-name: com.mysql.jdbc.Driver
                names: datasource1
                url:
                username:
                password:
                type: com.alibaba.druid.pool.DruidDataSource
            name2:
                driver-class-name: com.mysql.jdbc.Driver
                names: datasource2
                url: 
                username: 
                password:
                type: com.alibaba.druid.pool.DruidDataSource
    数据源注册 DynamicDataSourceRegister.java
    public class DynamicDataSourceRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
    
        private org.slf4j.Logger logger = LoggerFactory.getLogger(DynamicDataSourceRegister.class);
        public static  Environment environment;
        //指定默认数据源(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);
            this.environment = environment;
        }
    
        private void initDefaultDataSource(Environment env) {
            // 读取主数据源
            Map<String, Object> dsMap = new HashMap<>();
            dsMap.put("driver", env.getProperty("spring.datasource.driver-class-name"));
            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");
            if(StringUtil.isNotEmpty(dsPrefixs)) {
                for (String dsPrefix : dsPrefixs.split(",")) {
                    // 多个数据源
                    Map<String, Object> dsMap = new HashMap<>();
                    dsMap.put("driver", env.getProperty("slave.datasource." + dsPrefix + ".driver-class-name"));
                    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;
        }
    }

    动态数据源上下文管理:DynamicDataSourceContextHolder.java

    public class DynamicDataSourceContextHolder {//存放当前线程使用的数据源类型信息
        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);
        }
    }
    动态数据源  DynamicDataSource.java  -- AbstractRoutingDataSource(每执行一次数据库,动态获取DataSource)
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            return DynamicDataSourceContextHolder.getDataSourceType();
        }
    }
    动态数据源通知 DynamicDataSourceAspect.java
    @Aspect
    @Order(-1)//保证在@Transactional之前执行
    @Component
    public class DynamicDataSourceAspect {//改变数据源
        public void changeDataSource( String  targetDataSource) {
            if (StringUtil.isNotEmpty(targetDataSource) && DynamicDataSourceContextHolder.isContainsDataSource(targetDataSource)) {
                DynamicDataSourceContextHolder.setDataSourceType(targetDataSource);
            }
        }
    
        public void clearDataSource( String  targetDataSource) {
            DynamicDataSourceContextHolder.clearDataSourceType();
        }
    }

    换源API调用:

    @Autowired
    private DynamicDataSourceAspect dynamicDataSourceAspect;
    使用: dynamicDattaSourceAspect.changeDataSource(##数据源名称##);
    -----查询SQL业务----- dynamicDattaSourceAspect.clearDataSource(##数据源名称##);
    
    
  • 相关阅读:
    GitLab用户权限管理
    类似vant中的tab实现
    Gitgitee/github/gitlab账号分离
    Vim操作
    partition by 用法
    crontab执行feat_gen.sh时,报错找不到pyspark
    SQL同一个字段出现null和0值,有何区别,原因是什么?left join导致null值出现,case when导致0值出现
    linux 定时任务crontab的用法
    卡方检验
    ROC与AUC
  • 原文地址:https://www.cnblogs.com/feecy/p/11847207.html
Copyright © 2020-2023  润新知