达梦 数据库与mysql 多数据源整合

数据源 可自由切换 最好有demo参考 后期可能会加入 es 等

第一步:手动清除线程变量副本,调用clearDataSourceType方法

package com.cplink.framework.datasource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 数据源切换处理
 * 
 * @author ruoyi
 */
public class DynamicDataSourceContextHolder
{
    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);

    /**
     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
     *  所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
     */
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    /**
     * 设置数据源的变量
     */
    public static void setDataSourceType(String dsType)
    {
        log.info("切换到{}数据源", dsType);
        CONTEXT_HOLDER.set(dsType);
    }

    /**
     * 获得数据源的变量
     */
    public static String getDataSourceType()
    {
        return CONTEXT_HOLDER.get();
    }

    /**
     * 清空数据源变量
     */
    public static void clearDataSourceType()
    {
        CONTEXT_HOLDER.remove();
    }
}

第二步:准备数据源连接信息,包括:数据源名称(任取,不重名即可)、用户名、密码、url、数据库驱动(由数据库库类型代码转换,写mysql即可)

第三步:写一个继承AbstractRoutingDataSource的类,并连接数据源连接

package com.cplink.framework.datasource;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
import com.cplink.common.constant.Constants;
import com.cplink.common.utils.StringUtils;
import com.cplink.framework.config.properties.DruidProperties;
import com.cplink.framework.web.domain.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 动态数据源
 * 
 * @author ruoyi
 */
public class DynamicDataSource extends AbstractRoutingDataSource
{
    private final Log log = LogFactory.getLog(DynamicDataSource.class);
    private Map<Object, Object> dynamicTargetDataSources;

    @Autowired
    private DruidProperties druidProperties;

    public DynamicDataSource(javax.sql.DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
    {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey()
    {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }


    @Override
    public void setTargetDataSources(Map<Object, Object> targetDataSources) {
        super.setTargetDataSources(targetDataSources);
        this.dynamicTargetDataSources = targetDataSources;
    }


    /**
     * 检查并创建数据源(数据源存在不需要在创建)
     * @param dataSource DataBaseSource实体类信息
     * @param boo 是否默认数据目标源配置(true:系统默认连接信息,false自定义连接信息)
     * @param targetDataSources 当boo为false时用此源扩展信息
     * @throws Exception
     */
    public void createDataSourceWithCheck(DataSource dataSource, boolean boo, DruidDataSource targetDataSources) throws Exception {
        if(StringUtils.isNull(dataSource) || StringUtils.isEmpty(dataSource.getDataSourceId())){
            log.info("数据源基本配置信息不能为空");
            throw new Exception("数据源基本配置信息不能为空");
        }
        String datasourceId = dataSource.getDataSourceId();
        log.info("正在检查数据源:"+datasourceId);
        if(StringUtils.isEmpty(this.dynamicTargetDataSources))
            this.dynamicTargetDataSources = new HashMap<Object, Object>();
        Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
        //不存在'datasourceId'数据源,新建数据源
        if (!dynamicTargetDataSources2.containsKey(datasourceId)) {
            createDataSource(dataSource,boo,targetDataSources);
            return;
        }
        log.info("数据源"+datasourceId+"之前已经创建,准备测试数据源是否正常...");
        DruidDataSource druidDataSource = (DruidDataSource) dynamicTargetDataSources2.get(datasourceId);
        boolean rightFlag = true;
        Connection connection = null;
        try {
            log.info("准备获取数据库连接...");
            connection = druidDataSource.getConnection();
            log.info("数据源"+datasourceId+"正常");
        } catch (Exception e) {
            log.error(e.getMessage(),e); //把异常信息打印到日志文件
            rightFlag = false;
            log.info("缓存数据源"+datasourceId+"已失效,准备删除...");
            if(delDatasources(datasourceId)) {
                log.info("缓存数据源删除成功");
            } else {
                log.info("缓存数据源删除失败");
            }
        } finally {
            if(null != connection) {
                connection.close();
            }
        }
        if(rightFlag) {
            log.info("不需要重新创建数据源");
            return;
        }
        log.info("准备重新创建数据源...");
        createDataSource(dataSource,boo,targetDataSources);
        log.info("重新创建数据源完成");
    }

    /**
     * 创建数据源
     * @param dataSource
     * @throws Exception
     */
    public void createDataSource(DataSource dataSource, boolean boo, DruidDataSource targetDataSources) throws Exception {
        if(StringUtils.isNull(dataSource) || StringUtils.isEmpty(dataSource.getDataSourceId())){
            log.info("数据源基本配置信息不能为空");
            throw new Exception("数据源基本配置信息不能为空");
        }
        String datasourceId = dataSource.getDataSourceId();
        log.info("准备创建数据源"+datasourceId);
        testParamBoo(dataSource);
        if(!testDatasource(dataSource.getUserName(),dataSource.getPassWord(),dataSource.getUrl(),dataSource.getDataBaseType())) {
            log.error("数据源配置有错误");
            throw new Exception("数据源配置有错误");
        }
        boolean result = this.initDataSource(dataSource,boo,targetDataSources);
        if(!result) {
            log.error("数据源"+datasourceId+"配置正确,但是创建失败");
            throw new Exception("数据源"+datasourceId+"配置正确,但是创建失败");
        }
    }

    /**
     * 初始化数据源
     * @param dataBaseSource
     * @param boo 是否默认数据目标源配置(true:系统默认连接信息,false自定义连接信息)
     * @param targetDataSources 当boo为false时此源必填
     * @return
     */
    public boolean initDataSource(DataSource dataBaseSource, boolean boo, DruidDataSource targetDataSources)throws Exception {
        if(StringUtils.isNull(dataBaseSource) || StringUtils.isEmpty(dataBaseSource.getDataSourceId())){
            log.info("数据源基本配置信息不能为空");
            throw new Exception("数据源基本配置信息不能为空");
        }
        String key = dataBaseSource.getDataSourceId();
        DruidDataSource druidDataSource = null;
        if(!boo){
            //自定义数据源信息
            druidDataSource = getBaseDataSource(targetDataSources,dataBaseSource);
        }else{
            //默认数据源信息(除基本信息外,如用户名、密码、源名称、url连接信息、驱动)
            DruidDataSource druidData = new DruidDataSource();
            DruidDataSource dataSource = druidProperties.dataSource(druidData);
            druidDataSource = getBaseDataSource(dataSource,dataBaseSource);
        }
        if(StringUtils.isNull(druidDataSource)){
            log.error("数据源驱动配置错误");
            return false;
        }
        try {
            //数据源配置初始化
            druidDataSource.init();
        } catch (Exception e) {
            log.error("数据源配置初始化错误:".concat(e + ""));
            return false;
        }
        if(StringUtils.isEmpty(this.dynamicTargetDataSources))
            this.dynamicTargetDataSources = new HashMap<Object, Object>();
        this.dynamicTargetDataSources.put(key, druidDataSource);
        setTargetDataSources(this.dynamicTargetDataSources);// 将map赋值给父类的TargetDataSources
        super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
        log.info(key.concat("数据源初始化成功"));
        return true;
    }

    /**
     * 删除数据源
     * @param datasourceid
     * @return
     */
    public boolean delDatasources(String datasourceid) {
        if(StringUtils.isEmpty(this.dynamicTargetDataSources))
            this.dynamicTargetDataSources = new HashMap<Object, Object>();
        Map<Object, Object> dynamicTargetDataSources2 = this.dynamicTargetDataSources;
        if (!dynamicTargetDataSources2.containsKey(datasourceid))
            return false;
        Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
        for (DruidDataSource l : druidDataSourceInstances) {
            if (datasourceid.equals(l.getName())) {
                dynamicTargetDataSources2.remove(datasourceid);
                DruidDataSourceStatManager.removeDataSource(l);
                setTargetDataSources(dynamicTargetDataSources2);// 将map赋值给父类的TargetDataSources
                super.afterPropertiesSet();// 将TargetDataSources中的连接信息放入resolvedDataSources管理
                return true;
            }
        }
        return false;
    }

    /**
     * 测试数据源配置
     * @param userName 用户名
     * @param passWord 密码
     * @param url url
     * @param type 数据库类型
     * @return
     */
    public boolean testDatasource(String userName, String passWord, String url, String type){
        String driveClass = getDriveClass(type);
        if(Constants.FAIL.equals(driveClass))
            return false;
        try { // 排除连接不上的错误
            Class.forName(driveClass);
            DriverManager.getConnection(url, userName, passWord);// 相当于连接数据库
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 根据类型转换数据库驱动
     * @param databasetype
     * @return
     */
    private String getDriveClass(String databasetype){
        if("mysql".equalsIgnoreCase(databasetype))
            return Constants.MYSQL_DRIVER;
        if("oracle".equalsIgnoreCase(databasetype))
            return Constants.ORACLE_DRIVER;
        if("sqlserver".equalsIgnoreCase(databasetype))
            return Constants.SQLSERVER_DRIVER;
        return Constants.FAIL;
    }


    /**
     * 封装数据源连接信息
     * @param druidDataSource 自定义的连接信息或者默认的本系统连接信息
     * @param dataSource 基本的数据源信息(包含数据驱动、数据源key、url连接信息、用户名、密码)
     * @return
     */
    private DruidDataSource getBaseDataSource(DruidDataSource druidDataSource, DataSource dataSource)throws Exception{
        testParamBoo(dataSource);
        druidDataSource.setName(dataSource.getDataSourceId());
        String driveClass = getDriveClass(dataSource.getDataBaseType());
        if(Constants.FAIL.equals(driveClass))
            return null;
        druidDataSource.setDriverClassName(driveClass);
        druidDataSource.setUrl(dataSource.getUrl());
        druidDataSource.setUsername(dataSource.getUserName());
        druidDataSource.setPassword(dataSource.getPassWord());
        return druidDataSource;
    }

    private void testParamBoo(DataSource dataSource)throws Exception{
        if(StringUtils.isNull(dataSource) || StringUtils.isEmpty(dataSource.getDataSourceId())||StringUtils.isEmpty(dataSource.getDataBaseType())|| StringUtils.isEmpty(dataSource.getUserName())|| StringUtils.isEmpty(dataSource.getPassWord())|| StringUtils.isEmpty(dataSource.getUrl())){
            log.info("数据源基本配置信息不能为空");
            throw new Exception("数据源基本配置信息不能为空");
        }
    }
}

第五步:切换数据源

DynamicDataSourceContextHolder.clearDataSourceType();

String key = "test1";
String username = "test1";
String password = "test1";
String url = "";
String dataType = "mysql";

DataSource dataBaseSource = new DataSource();
dataBaseSource.setDataSourceId(key);
dataBaseSource.setUrl(url);
dataBaseSource.setDataBaseType(dataType);
dataBaseSource.setUserName(username);
dataBaseSource.setPassWord(password);

try{
            //创建数据源连接&检查 若存在则不需重新创建
           dynamicDataSource.createDataSourceWithCheck(dataBaseSource,true,null);
            //切换到该数据源
            DynamicDataSourceContextHolder.setDataSourceType(key);
        } catch (Exception e) {
            e.printStackTrace();
        }

//下面写执行切换了数据源之后的表的操作

另外DruidProperties类

package com.cplink.framework.config.properties;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;

/**
 * druid 配置属性
 * 
 * @author ruoyi
 */
@Configuration
public class DruidProperties
{
    @Value("${spring.datasource.druid.initialSize}")
    private int initialSize;

    @Value("${spring.datasource.druid.minIdle}")
    private int minIdle;

    @Value("${spring.datasource.druid.maxActive}")
    private int maxActive;

    @Value("${spring.datasource.druid.maxWait}")
    private int maxWait;

    @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
    private int maxEvictableIdleTimeMillis;

    @Value("${spring.datasource.druid.validationQuery}")
    private String validationQuery;

    @Value("${spring.datasource.druid.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.datasource.druid.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.datasource.druid.testOnReturn}")
    private boolean testOnReturn;

    public DruidDataSource dataSource(DruidDataSource datasource)
    {
        /** 配置初始化大小、最小、最大 */
        datasource.setInitialSize(initialSize);
        datasource.setMaxActive(maxActive);
        datasource.setMinIdle(minIdle);

        /** 配置获取连接等待超时的时间 */
        datasource.setMaxWait(maxWait);

        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);

        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);

        /**
         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
         */
        datasource.setValidationQuery(validationQuery);
        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
        datasource.setTestWhileIdle(testWhileIdle);
        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnBorrow(testOnBorrow);
        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnReturn(testOnReturn);
        return datasource;
    }
}

基本就这些,事实上需要做的就是创建一个管理连接线程副本,用多数据源的信息测试连接,成功就初始化,在切换数据源,就可以在相应的数据源上进行表的操作。

 

您好,我是有问必答小助手,您的问题已经有小伙伴解答了,您看下是否解决,可以追评进行沟通哦~

如果有您比较满意的答案 / 帮您提供解决思路的答案,可以点击【采纳】按钮,给回答的小伙伴一些鼓励哦~~

ps:问答VIP仅需29元,即可享受5次/月 有问必答服务,了解详情>>>https://vip.csdn.net/askvip?utm_source=1146287632