快上网专注成都网站设计 成都网站制作 成都网站建设
成都网站建设公司服务热线:028-86922220

网站建设知识

十年网站开发经验 + 多家企业客户 + 靠谱的建站团队

量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决

springboot中怎么实现动态数据源

springboot中怎么实现动态数据源,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。

成都创新互联公司服务项目包括德惠网站建设、德惠网站制作、德惠网页制作以及德惠网络营销策划等。多年来,我们专注于互联网行业,利用自身积累的技术优势、行业经验、深度合作伙伴关系等,向广大中小型企业、政府机构等提供互联网行业的解决方案,德惠网站推广取得了明显的社会效益与经济效益。目前,我们服务的客户以成都为中心已经辐射到德惠省份的部分城市,未来相信会继续扩大服务区域并继续获得客户的支持与信任!

/**
 * 作用:保存一个线程安全的DatabaseType容器
 */
public class DatabaseContextHolder {
    private static final ThreadLocal contextHolder = new ThreadLocal<>();

    /**
     * 当需要操作数据库前,也就是调用mapper.c/r/u/d方法前,可以调用该方法
     * 该方法的作用是设置需要连接的数据库
     * 由于是线程安全,如果一个新的controller连接请求,在操作数据库前没有显式的调用该方法,则get到的databaseType将会为null
     * 但这并不影响数据库的操作,因为在数据源的设置中已经设置了默认的数据源
     * 当在同一个线程中(也就是本系统controller的同一个请求处理中),如果该方法被调用过
     * 则后面的数据库操作,也就是mapper.c/r/u/d的时,get到的都是set好的数据源,除非再次显式的调用这个set方法改变数据源
     */
    public static void setDatabaseType(String type) {
        contextHolder.set(type);
    }

    /**
     * 当通过mapper.c/r/u/d方法等操作数据库时
     * 该方法会自动被determineCurrentLookupKey方法调用到
     * determineCurrentLookupKey是重写了Spring里的AbstractRoutingDataSource类的determineCurrentLookupKey方法
     *
     * @see DynamicDataSource
     */
    public static String getDatabaseType() {
        return contextHolder.get();
    }
}


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 数据源工具类
 */
@Configuration
@Slf4j
public class DataSourceUtil {

    @Autowired
    private Environment env;

    //默认数据源
    private DataSource defaultDataSource;

    //用户自定义数据源
    private Map slaveDataSources = new HashMap<>();

    /**
     * @see org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource() throws Exception {
        initDefaultDataSource();
        initSlaveDataSources();

        Map targetDataSources = new HashMap<>();
        targetDataSources.put("", defaultDataSource);
        targetDataSources.putAll(slaveDataSources);

        DynamicDataSource dataSource = new DynamicDataSource();
        dataSource.setDefaultTargetDataSource(defaultDataSource);// 该方法是AbstractRoutingDataSource的方法,默认数据源
        dataSource.setTargetDataSources(targetDataSources);// 该方法是AbstractRoutingDataSource的方法,数据源map
        return dataSource;
    }

    private void initDefaultDataSource() {
        // 读取主数据源
        Map 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() {
        // 读取配置文件获取更多数据源
        String dsPrefixs = env.getProperty("slave.datasource.names");
        for (String dsPrefix : dsPrefixs.split(",")) {
            // 多个数据源
            Map 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);
        }
    }

    //指定默认数据源(springboot2.0默认数据源是hikari如何想使用其他数据源可以自己配置)
    private static final String DATASOURCE_TYPE_DEFAULT = "com.zaxxer.hikari.HikariDataSource";

    private DataSource buildDataSource(Map dataSourceMap) {
        try {
            Object type = dataSourceMap.get("type");
            if (type == null) {
                type = DATASOURCE_TYPE_DEFAULT;// 默认DataSource
            }
            log.debug("data source type:{}", type);
            Class dataSourceType;
            dataSourceType = (Class) Class.forName((String) type);
            String driverClassName = dataSourceMap.get("driver");
            String url = dataSourceMap.get("url");
            String username = dataSourceMap.get("username");
            String password = dataSourceMap.get("password");
            // 自定义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;
    }
}


import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * 动态数据源(需要继承AbstractRoutingDataSource)
 */
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DatabaseContextHolder.getDatabaseType();
    }
}


    @Value("#{'${slave.datasource.names}'.split(',')}")
    private List dsNameList;

    public int monitor() {
        // 默认数据源
        if (heartBeatDatabase(Strings.EMPTY) == 0)
            isError = true;

        // 其他数据源
        for (String dsName : dsNameList) {
            if (heartBeatDatabase(dsName) == 0)
                isError = true;
        }

        // 出现异常
        if (isError) {
            isError = false;
            return 0;
        }

        return 1;
    }

    private int heartBeatDatabase(String dsName) {
        try {
            DatabaseContextHolder.setDatabaseType(dsName);
            return monitorDao.select();
        }
        catch (Exception e) {
            log.error("heartbeat error!");
            try {
                sendMail(dsName);
            } catch (MessagingException e1) {
                log.error("send mail error!", e);
            }
        }
        return 0;
    }


# MySQL配置
spring.datasource.url=jdbc:mysql://130.51.23.249:3306/vacdb01?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root1
spring.datasource.password=
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# ds1,ds2等其他数据源,记得不要漏!否则下面配置了也是白配。
slave.datasource.names=ds1,ds2,ds3
# ds1
slave.datasource.ds1.driver=com.mysql.cj.jdbc.Driver
slave.datasource.ds1.url=jdbc:mysql://130.51.23.249:3306/flowable?useSSL=false
slave.datasource.ds1.username=flowable
slave.datasource.ds1.password=
# ds2
slave.datasource.ds2.driver=com.mysql.cj.jdbc.Driver
slave.datasource.ds2.url=jdbc:mysql://132.120.2.134:3300/motor?useSSL=false
slave.datasource.ds2.username=motor
slave.datasource.ds2.password=
# ds3
slave.datasource.ds3.driver=com.mysql.cj.jdbc.Driver
slave.datasource.ds3.url=jdbc:mysql://130.51.23.249:8066/VACDB?useUnicode=true&characterEncoding=utf-8
slave.datasource.ds3.username=vac
slave.datasource.ds3.password=

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注创新互联行业资讯频道,感谢您对创新互联的支持。


名称栏目:springboot中怎么实现动态数据源
路径分享:http://6mz.cn/article/jdpeps.html

其他资讯