千家信息网

springboot中怎么实现动态数据源

发表于:2025-02-07 作者:千家信息网编辑
千家信息网最后更新 2025年02月07日,springboot中怎么实现动态数据源,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。/** * 作用:保存一个线程安全
千家信息网最后更新 2025年02月07日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@Slf4jpublic 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-8spring.datasource.username=root1spring.datasource.password=spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# ds1,ds2等其他数据源,记得不要漏!否则下面配置了也是白配。slave.datasource.names=ds1,ds2,ds3# ds1slave.datasource.ds1.driver=com.mysql.cj.jdbc.Driverslave.datasource.ds1.url=jdbc:mysql://130.51.23.249:3306/flowable?useSSL=falseslave.datasource.ds1.username=flowableslave.datasource.ds1.password=# ds2slave.datasource.ds2.driver=com.mysql.cj.jdbc.Driverslave.datasource.ds2.url=jdbc:mysql://132.120.2.134:3300/motor?useSSL=falseslave.datasource.ds2.username=motorslave.datasource.ds2.password=# ds3slave.datasource.ds3.driver=com.mysql.cj.jdbc.Driverslave.datasource.ds3.url=jdbc:mysql://130.51.23.249:8066/VACDB?useUnicode=true&characterEncoding=utf-8slave.datasource.ds3.username=vacslave.datasource.ds3.password=

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

0