国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

SpringBoot從數(shù)據(jù)庫讀取數(shù)據(jù)數(shù)據(jù)源配置信息,動態(tài)切換數(shù)據(jù)源

這篇具有很好參考價值的文章主要介紹了SpringBoot從數(shù)據(jù)庫讀取數(shù)據(jù)數(shù)據(jù)源配置信息,動態(tài)切換數(shù)據(jù)源。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

準(zhǔn)備多個數(shù)據(jù)庫

? ? ? ? 首先準(zhǔn)備多個數(shù)據(jù)庫,主庫smiling-datasource,其它庫test1、test2、test3

? ? ? ? 接下來,我們在主庫smiling-datasource中,創(chuàng)建表databasesource,用于存儲多數(shù)據(jù)源相關(guān)信息。表結(jié)構(gòu)設(shè)計如下

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

? ? ? ? 創(chuàng)建好表之后,向表databasesource中存儲test1、test2、test3三個數(shù)據(jù)庫的相關(guān)配置信息

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

? ? ? ? 在主庫的表databasesource中存儲好數(shù)據(jù)源信息后,接下來分別在test1、test2、test3以及主庫smiling-datasource中都創(chuàng)建sys_user數(shù)據(jù)表,用于后續(xù)測試數(shù)據(jù)源切換是否正常。sys_user的表結(jié)構(gòu)如下所示

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

? ? ? ? 創(chuàng)建好sys_user之后,分別向sys_user表中添加一條數(shù)據(jù),添加的數(shù)據(jù)中分表用不同的內(nèi)容表示屬于哪個庫,方便后續(xù)測試。

依賴

? ? ? ? 該實現(xiàn)主要用到JDK1.8、spring-boot-starter-parent的版本為2.2.0.RELEASE,除此之外需要用到mysql、druid以及mybatis-plus的依賴

配置

? ? ? ? 在配置文件application.yml中主要配置主庫的數(shù)據(jù)源信息,配置如下

spring:
  aop:
    proxy-target-class: true   #true為使用CGLIB代理
  datasource:
    url: jdbc:mysql://localhost:3306/smiling-datasource?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull
    username: root
    password: zhangpei@123
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      initial-size: 5 #初始化大小
      min-idle: 5 #最小連接數(shù)
      max-active: 20  #最大連接數(shù)
      time-between-eviction-runs-millis: 60000  #配置間隔多久進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接,單位毫秒
      min-evictable-idle-time-millis: 300000  #配置一個連接在池中最小生存的時間,單位毫秒
      validation-query: SELECT 1 FROM DUAL
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      pool-prepared-statements: true
      max-pool-prepared-statement-per-connection-size: 20
      filters: stat,wall,log4j  #配置監(jiān)控統(tǒng)計攔截的filters,去掉后監(jiān)控界面sql無法統(tǒng)計,wall用于防火墻
      connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 #通過該屬性打開mergeSQl功能:慢sql記錄功能
      use-global-data-source-stat: true #合并多個DruidDataSource的監(jiān)控數(shù)據(jù)
      max-wait: 60000 #配置獲取連接等待超時時間
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapping/*.xml

基類DataSource

? ? ? ? 創(chuàng)建類DataSource,用于數(shù)據(jù)源信息的裝配

@Data
@ToString
public class DataSource {

    String datasourceId;
    String url;
    String username;
    String password;
    String code;
    String databasetype;
    String driverclass;
    String key;

}

DruidDBConfig配置類

? ? ? ? 該配置類主要用于配置默認(rèn)的主數(shù)據(jù)源信息,配置Druid數(shù)據(jù)庫連接池,配置sql工廠加載mybatis的文件,掃描實體類等

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
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 org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 配置默認(rèn)數(shù)據(jù)源
 * 配置Druid數(shù)據(jù)庫連接池
 * 配置sql工廠加載mybatis的文件,掃描實體等
 *
 * @author smiling
 * @date 2023/10/7 19:04
 */
@Slf4j
@Configuration
@EnableTransactionManagement
public class DruilDBConfig {

    @Value("${spring.datasource.url}")
    private String dbUrl;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
    // 連接池連接信息
    @Value("${spring.datasource.druid.initial-size}")
    private int initialSize;
    @Value("${spring.datasource.druid.min-idle}")
    private int minIdle;
    @Value("${spring.datasource.druid.max-active}")
    private int maxActive;
    @Value("${spring.datasource.druid.max-wait}")
    private int maxWait;

    @Bean
    @Primary
    @Qualifier("mainDataSource")
    public DataSource dataSource() throws SQLException {
        DruidDataSource dataSource = new DruidDataSource();
        // 基礎(chǔ)連接信息
        dataSource.setUrl(this.dbUrl);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClassName);
        // 連接池連接信息
        dataSource.setInitialSize(initialSize);
        dataSource.setMinIdle(minIdle);
        dataSource.setMaxActive(maxActive);
        dataSource.setMaxWait(maxWait);
        dataSource.setPoolPreparedStatements(true); //是否緩存preparedStatement,也就是PSCache。PSCache對支持游標(biāo)的數(shù)據(jù)庫性能提升巨大,比如說oracle。在mysql下建議關(guān)閉。
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
        //  datasource.setConnectionProperties("oracle.net.CONNECT_TIMEOUT=6000;oracle.jdbc.ReadTimeout=60000");//對于耗時長的查詢sql,會受限于ReadTimeout的控制,單位毫秒
        dataSource.setConnectionProperties("druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000");//對于耗時長的查詢sql,會受限于ReadTimeout的控制,單位毫秒
        dataSource.setTestOnBorrow(true); //申請連接時執(zhí)行validationQuery檢測連接是否有效,這里建議配置為TRUE,防止取到的連接不可用
        dataSource.setTestWhileIdle(true);//建議配置為true,不影響性能,并且保證安全性。申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測連接是否有效。
        String validationQuery = "select 1 from dual";
        dataSource.setValidationQuery(validationQuery); //用來檢測連接是否有效的sql,要求是一個查詢語句。如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會起作用。
        dataSource.setFilters("stat,wall");//屬性類型是字符串,通過別名的方式配置擴(kuò)展插件,常用的插件有:監(jiān)控統(tǒng)計用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
        dataSource.setTimeBetweenEvictionRunsMillis(60000); //配置間隔多久才進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接,單位是毫秒
        dataSource.setMinEvictableIdleTimeMillis(180000); //配置一個連接在池中最小生存的時間,單位是毫秒,這里配置為3分鐘180000
        dataSource.setKeepAlive(true); //打開druid.keepAlive之后,當(dāng)連接池空閑時,池中的minIdle數(shù)量以內(nèi)的連接,空閑時間超過minEvictableIdleTimeMillis,則會執(zhí)行keepAlive操作,即執(zhí)行druid.validationQuery指定的查詢SQL,一般為select * from dual,只要minEvictableIdleTimeMillis設(shè)置的小于防火墻切斷連接時間,就可以保證當(dāng)連接空閑時自動做保活檢測,不會被防火墻切斷
        dataSource.setRemoveAbandoned(true); //是否移除泄露的連接/超過時間限制是否回收。
        dataSource.setRemoveAbandonedTimeout(3600); //泄露連接的定義時間(要超過最大事務(wù)的處理時間);單位為秒。這里配置為1小時
        dataSource.setLogAbandoned(true); //移除泄露連接發(fā)生是是否記錄日志
        return dataSource;
    }

    /**
     * 注冊一個statViewServlet druid監(jiān)控頁面配置
     * 賬號密碼配置
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean druidStatViewServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        servletRegistrationBean.addInitParameter("loginUsername", "admin");
        servletRegistrationBean.addInitParameter("loginPassword", "123456");
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        return servletRegistrationBean;
    }

    /**
     * 注冊一個:filterRegistrationBean   druid監(jiān)控頁面配置2-允許頁面正常瀏覽
     *
     * @return filter registration bean
     */
    @Bean
    public FilterRegistrationBean druidStatFilter() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        // 添加過濾規(guī)則.
        filterRegistrationBean.addUrlPatterns("/*");
        // 添加不需要忽略的格式信息.
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }

    @Bean(name = "dynamicDataSource")
    @Qualifier("dynamicDataSource")
    public DynamicDataSource dynamicDataSource() throws SQLException {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDebug(false);
        //配置缺省的數(shù)據(jù)源
        // 默認(rèn)數(shù)據(jù)源配置 DefaultTargetDataSource
        dynamicDataSource.setDefaultTargetDataSource(dataSource());
        Map<Object, Object> targetDataSources = new HashMap<Object, Object>();
        //額外數(shù)據(jù)源配置 TargetDataSources
        targetDataSources.put("mainDataSource", dataSource());
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        //解決手動創(chuàng)建數(shù)據(jù)源后字段到bean屬性名駝峰命名轉(zhuǎn)換失效的問題
        sqlSessionFactoryBean.setConfiguration(configuration());

        // 設(shè)置mybatis的主配置文件
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // Resource mybatisConfigXml = resolver.getResource("classpath:mybatis/mybatis-config.xml");
        //  sqlSessionFactoryBean.setConfigLocation(mybatisConfigXml);
        // 設(shè)置別名包
        //  sqlSessionFactoryBean.setTypeAliasesPackage("com.testdb.dbsource.pojo");

        //手動配置mybatis的mapper.xml資源路徑,如果單純使用注解方式,不需要配置該行
         sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mapping/*.xml"));
        return sqlSessionFactoryBean.getObject();
    }


    /**
     * 讀取駝峰命名設(shè)置
     *
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = "mybatis-plus.configuration")
    public org.apache.ibatis.session.Configuration configuration() {
        return new org.apache.ibatis.session.Configuration();
    }

}

DBContextHolder類

? ? ? ? 該類主要用于手動切換數(shù)據(jù)源

import lombok.extern.slf4j.Slf4j;

/**
 * @author smiling
 * @date 2023/10/7 19:16
 */
@Slf4j
public class DBContextHolder {

    //對當(dāng)前線程的操作-線程安全的
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    //調(diào)用此方法,切換數(shù)據(jù)源
    public static void setDataSource(String dataSource){
        contextHolder.set(dataSource);
        log.info("已切換到數(shù)據(jù)源:{}",dataSource);
    }

    //獲取數(shù)據(jù)源
    public static String getDataSource(){
        return contextHolder.get();
    }

    //刪除數(shù)據(jù)源
    public static void clearDataSource(){
        contextHolder.remove();
        log.info("已切換到主數(shù)據(jù)源");
    }

}

DynamicDataSource類

? ? ? ? 該類實現(xiàn)手動加載默認(rèn)數(shù)據(jù)源、創(chuàng)建數(shù)據(jù)源連接、檢查數(shù)據(jù)源連接、刪除數(shù)據(jù)源連接等

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.stat.DruidDataSourceStatManager;
import com.smiling.datasource.model.DataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.util.ObjectUtils;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Map;
import java.util.Set;

/**
 * 手動加載默認(rèn)數(shù)據(jù)源
 * 創(chuàng)建數(shù)據(jù)源連接
 * 檢查數(shù)據(jù)源連接
 * 刪除數(shù)據(jù)源連接等
 *
 * @author smiling
 * @date 2023/10/8 11:03
 */
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {

    private boolean debug = true;

    private Map<Object, Object> dynamicTargetDataSources;

    private Object dynamicDefaultTargetDataSource;

    @Override
    protected Object determineCurrentLookupKey() {
        String datasource = DBContextHolder.getDataSource();
        if (!ObjectUtils.isEmpty(datasource)) {
            Map<Object, Object> targetDataSource = this.dynamicTargetDataSources;
            if (targetDataSource.containsKey(datasource)) {
                log.info("當(dāng)前數(shù)據(jù)源:" + datasource);
            } else {
                log.info("不存在的數(shù)據(jù)源");
                return null;
            }
        } else {
            log.info("當(dāng)前數(shù)據(jù)源:默認(rèn)數(shù)據(jù)源");
        }
        return datasource;
    }

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

    //創(chuàng)建數(shù)據(jù)源
    public boolean createDataSource(String key, String driveClass, String url, String username, String password, String databasetype) {
        try {
            try {
                Class.forName(driveClass);
                DriverManager.getConnection(url, username, password);
            } catch (Exception e) {
                return false;
            }
            @SuppressWarnings("resource")
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setName(key);
            druidDataSource.setDriverClassName(driveClass);
            druidDataSource.setUrl(url);
            druidDataSource.setUsername(username);
            druidDataSource.setPassword(password);
            druidDataSource.setInitialSize(1); //初始化時建立物理連接的個數(shù)。初始化發(fā)生在顯示調(diào)用init方法,或者第一次getConnection時
            druidDataSource.setMaxActive(20); //最大連接池數(shù)量
            druidDataSource.setMaxWait(60000); //獲取連接時最大等待時間,單位毫秒。當(dāng)鏈接數(shù)已經(jīng)達(dá)到了最大鏈接數(shù)的時候,應(yīng)用如果還要獲取鏈接就會出現(xiàn)等待的現(xiàn)象,等待鏈接釋放并回到鏈接池,如果等待的時間過長就應(yīng)該踢掉這個等待,不然應(yīng)用很可能出現(xiàn)雪崩現(xiàn)象
            druidDataSource.setMinIdle(5); //最小連接池數(shù)量
            String validationQuery = "select 1 from dual";
            druidDataSource.setTestOnBorrow(true); //申請連接時執(zhí)行validationQuery檢測連接是否有效,這里建議配置為TRUE,防止取到的連接不可用
            druidDataSource.setTestWhileIdle(true);//建議配置為true,不影響性能,并且保證安全性。申請連接的時候檢測,如果空閑時間大于timeBetweenEvictionRunsMillis,執(zhí)行validationQuery檢測連接是否有效。
            druidDataSource.setValidationQuery(validationQuery); //用來檢測連接是否有效的sql,要求是一個查詢語句。如果validationQuery為null,testOnBorrow、testOnReturn、testWhileIdle都不會起作用。
            druidDataSource.setFilters("stat");//屬性類型是字符串,通過別名的方式配置擴(kuò)展插件,常用的插件有:監(jiān)控統(tǒng)計用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
            druidDataSource.setTimeBetweenEvictionRunsMillis(60000); //配置間隔多久才進(jìn)行一次檢測,檢測需要關(guān)閉的空閑連接,單位是毫秒
            druidDataSource.setMinEvictableIdleTimeMillis(180000); //配置一個連接在池中最小生存的時間,單位是毫秒,這里配置為3分鐘180000
            druidDataSource.setKeepAlive(true); //打開druid.keepAlive之后,當(dāng)連接池空閑時,池中的minIdle數(shù)量以內(nèi)的連接,空閑時間超過minEvictableIdleTimeMillis,則會執(zhí)行keepAlive操作,即執(zhí)行druid.validationQuery指定的查詢SQL,一般為select * from dual,只要minEvictableIdleTimeMillis設(shè)置的小于防火墻切斷連接時間,就可以保證當(dāng)連接空閑時自動做?;顧z測,不會被防火墻切斷
            druidDataSource.setRemoveAbandoned(true); //是否移除泄露的連接/超過時間限制是否回收。
            druidDataSource.setRemoveAbandonedTimeout(3600); //泄露連接的定義時間(要超過最大事務(wù)的處理時間);單位為秒。這里配置為1小時
            druidDataSource.setLogAbandoned(true); //移除泄露連接發(fā)生是是否記錄日志
            druidDataSource.init();
            this.dynamicTargetDataSources.put(key, druidDataSource);
            setTargetDataSources(this.dynamicTargetDataSources);// 將map賦值給父類的TargetDataSources
            super.afterPropertiesSet();// 將TargetDataSources中的連接信息放入resolvedDataSources管理
            log.info(key + "數(shù)據(jù)源初始化成功");
            return true;
        } catch (Exception e) {
            log.error(e + "");
            return false;
        }
    }

    //刪除數(shù)據(jù)源
    public boolean delDatasources(String datasourceid) {
        Map<Object, Object> targetDataSource = this.dynamicTargetDataSources;
        if (targetDataSource.containsKey(datasourceid)) {
            Set<DruidDataSource> druidDataSourceInstances = DruidDataSourceStatManager.getDruidDataSourceInstances();
            for (DruidDataSource source : druidDataSourceInstances) {
                if (datasourceid.equals(source.getName())) {
                    targetDataSource.remove(datasourceid);
                    DruidDataSourceStatManager.removeDataSource(source);
                    setTargetDataSources(targetDataSource);// 將map賦值給父類的TargetDataSources
                    super.afterPropertiesSet();// 將TargetDataSources中的連接信息放入resolvedDataSources管理
                    return true;
                }
            }
            return false;
        } else {
            return false;
        }
    }

    // 測試數(shù)據(jù)源連接是否有效
    public boolean testDatasource(String key, String driveClass, String url, String username, String password) {
        try {
            Class.forName(driveClass);
            DriverManager.getConnection(url, username, password);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    @Override
    public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        this.dynamicDefaultTargetDataSource = defaultTargetDataSource;
    }

    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    public boolean isDebug() {
        return debug;
    }

    public Map<Object, Object> getDynamicTargetDataSources() {
        return dynamicTargetDataSources;
    }

    public void setDynamicTargetDataSources(Map<Object, Object> dynamicTargetDataSources) {
        this.dynamicTargetDataSources = dynamicTargetDataSources;
    }

    public Object getDynamicDefaultTargetDataSource() {
        return dynamicDefaultTargetDataSource;
    }

    public void setDynamicDefaultTargetDataSource(Object dynamicDefaultTargetDataSource) {
        this.dynamicDefaultTargetDataSource = dynamicDefaultTargetDataSource;
    }

    public void createDataSourceWithCheck(DataSource dataSource) throws Exception {
        String datasourceId = dataSource.getDatasourceId();
        log.info("正在檢查數(shù)據(jù)源:" + datasourceId);
        Map<Object, Object> targetDataSources = this.dynamicTargetDataSources;
        if (targetDataSources.containsKey(datasourceId)) {
            log.info("數(shù)據(jù)源" + datasourceId + "之前已經(jīng)創(chuàng)建,準(zhǔn)備測試數(shù)據(jù)源是否正常...");
            //DataSource druidDataSource = (DataSource) dynamicTargetDataSources2.get(datasourceId);
            DruidDataSource druidDataSource = (DruidDataSource) targetDataSources.get(datasourceId);
            boolean rightFlag = true;
            Connection connection = null;
            try {
                log.info(datasourceId + "數(shù)據(jù)源的概況->當(dāng)前閑置連接數(shù):" + druidDataSource.getPoolingCount());
                long activeCount = druidDataSource.getActiveCount();
                log.info(datasourceId + "數(shù)據(jù)源的概況->當(dāng)前活動連接數(shù):" + activeCount);
                if (activeCount > 0) {
                    log.info(datasourceId + "數(shù)據(jù)源的概況->活躍連接堆棧信息:" + druidDataSource.getActiveConnectionStackTrace());
                }
                log.info("準(zhǔn)備獲取數(shù)據(jù)庫連接...");
                connection = druidDataSource.getConnection();
                log.info("數(shù)據(jù)源" + datasourceId + "正常");
            } catch (Exception e) {
                log.error(e.getMessage(), e); //把異常信息打印到日志文件
                rightFlag = false;
                log.info("緩存數(shù)據(jù)源" + datasourceId + "已失效,準(zhǔn)備刪除...");
                if (delDatasources(datasourceId)) {
                    log.info("緩存數(shù)據(jù)源刪除成功");
                } else {
                    log.info("緩存數(shù)據(jù)源刪除失敗");
                }
            } finally {
                if (null != connection) {
                    connection.close();
                }
            }
            if (rightFlag) {
                log.info("不需要重新創(chuàng)建數(shù)據(jù)源");
                return;
            } else {
                log.info("準(zhǔn)備重新創(chuàng)建數(shù)據(jù)源...");
                createDataSource(dataSource);
                log.info("重新創(chuàng)建數(shù)據(jù)源完成");
            }
        } else {
            createDataSource(dataSource);
        }

    }

    private void createDataSource(DataSource dataSource) throws Exception {
        String datasourceId = dataSource.getDatasourceId();
        log.info("準(zhǔn)備創(chuàng)建數(shù)據(jù)源" + datasourceId);
        String databasetype = dataSource.getDatabasetype();
        String username = dataSource.getUsername();
        String password = dataSource.getPassword();
        String url = dataSource.getUrl();
        String driveClass = "com.mysql.cj.jdbc.Driver";
        if (testDatasource(datasourceId, driveClass, url, username, password)) {
            boolean result = this.createDataSource(datasourceId, driveClass, url, username, password, databasetype);
            if (!result) {
                log.error("數(shù)據(jù)源" + datasourceId + "配置正確,但是創(chuàng)建失敗");
            }
        } else {
            log.error("數(shù)據(jù)源配置有錯誤");
        }
    }

}

切換數(shù)據(jù)源使用的方法

? ? ? ? 首先獲取主數(shù)據(jù)源的表databasesource里面的所有西悉尼,然后根據(jù)我們傳入對應(yīng)的數(shù)據(jù)源id進(jìn)行數(shù)據(jù)源的切換

DataSourceMapper

@Mapper
public interface DataSourceMapper {

    @Select("select * from databasesource")
    List<DataSource> get();    

}

DBChangeService

public interface DBChangeService {

    List<DataSource> get();

    boolean changeDb(String datasourceId) throws Exception;

}

DBChangeServiceImpl

@Service
public class DBChangeServiceImpl implements DBChangeService {

    private DataSourceMapper dataSourceMapper;

    private DynamicDataSource dynamicDataSource;

    public DBChangeServiceImpl(DataSourceMapper dataSourceMapper,
                                DynamicDataSource dynamicDataSource){

        this.dataSourceMapper = dataSourceMapper;
        this.dynamicDataSource = dynamicDataSource;

    }    

    @Override
    public List<DataSource> get() { return dataSourceMapper.get(); }

    @Override
    public boolean changeDb(String datasourceId) throws Exception {

        //默認(rèn)切換到主數(shù)據(jù)源,進(jìn)行整體資源的查找
        DBContextHolder.clearDataSource();
        List<DataSource> dataSourceList = dataSourceMapper.get();
        for(DataSource source : dataSourceList){
            if(source.getDatasourceId().equals(datasourceId)){
                System.out.println("需要使用的數(shù)據(jù)源已經(jīng)找到,datasourceId是:"+source.getDatasourceId());
                //創(chuàng)建數(shù)據(jù)源連接&檢查,若存在則不需要重新創(chuàng)建
                dynamicDataSource.createDataSourceWithCheck(source);
                //切換到該數(shù)據(jù)源
                DBContextHolder.setDataSource(source.getDatasourceId());
                return true;
            }
        }
        return false;
    
    }

}

實體類User

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

UserMapper

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

UserMapper.xml

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

DemoController

? ? ? ? 通過請求接口,通過控制臺日志打印可以看到數(shù)據(jù)源的切換信息

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

多數(shù)據(jù)源事務(wù)管理

? ? ? ? 實現(xiàn)動態(tài)數(shù)據(jù)源事務(wù),在類DruidDBConfig配置類中將我們實現(xiàn)的動態(tài)數(shù)據(jù)源加載類DynamicDataSource添加到數(shù)據(jù)事務(wù)管理器中

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端

? ? ? ? 上面配置還是單數(shù)據(jù)源事務(wù)生效,如果是多個數(shù)據(jù)源就不會生效。該句話的意思是,一個方法中,如果涉及到一個數(shù)據(jù)源,則事務(wù)生效,如果涉及到多個數(shù)據(jù)源,則事務(wù)不會在多個數(shù)據(jù)源中生效。

? ? ? ? 如果想要多個數(shù)據(jù)源事務(wù)一起生效,解決方案如下(注意是針對mybatis-plus框架)

? ? ? ? 找到DruidDBConfig配置類,將其中的SqlSessionFactoryBean調(diào)整為MybatisSqlSessionFactoryBean,如下

將數(shù)據(jù)庫連接信息存到表里實現(xiàn)切換數(shù)據(jù)源,數(shù)據(jù)庫,spring boot,后端文章來源地址http://www.zghlxwxcb.cn/news/detail-792091.html

到了這里,關(guān)于SpringBoot從數(shù)據(jù)庫讀取數(shù)據(jù)數(shù)據(jù)源配置信息,動態(tài)切換數(shù)據(jù)源的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 「數(shù)據(jù)庫、數(shù)據(jù)庫連接池、數(shù)據(jù)源」這些概念你真的理解了嗎?

    我學(xué)習(xí)的過程中,對于連接池和數(shù)據(jù)源分得不是很清楚,而且我發(fā)現(xiàn)有的人將數(shù)據(jù)庫等同于數(shù)據(jù)源,或者將數(shù)據(jù)源等同于連接池,實際上這些說法并不準(zhǔn)確。 在某次工作中,同事 A 說道,這個數(shù)據(jù)源不行,那么換一個數(shù)據(jù)源就可以了,結(jié)果我看他操作,原來是改寫了配置中的

    2023年04月21日
    瀏覽(19)
  • java serverlets使用數(shù)據(jù)源連接oracle數(shù)據(jù)庫,并執(zhí)行查詢操作代碼

    java serverlets使用數(shù)據(jù)源連接oracle數(shù)據(jù)庫,并執(zhí)行查詢操作代碼

    package chap03; import java.io.IOException; import java.io.PrintWriter; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.PreparedStatement; import java.sql.Statement; import java.util.*; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.Namin

    2024年02月08日
    瀏覽(26)
  • 自動生成數(shù)據(jù)庫設(shè)計文檔,支持多數(shù)據(jù)源批量生成(Word文檔)

    自動生成數(shù)據(jù)庫設(shè)計文檔,支持多數(shù)據(jù)源批量生成(Word文檔)

    ? ? ? 在做項目時通常使用PowerDesigner設(shè)計數(shù)據(jù)庫,但在項目完成交付項目給客戶的時候常常需要一份Word版本的數(shù)據(jù)庫文檔給客戶,你不能指望每個客戶都會用PowerDesigner,所以基于當(dāng)前開發(fā)數(shù)據(jù)庫生成數(shù)據(jù)庫文檔就是最佳選擇,如果手動編寫數(shù)據(jù)庫文檔那將是一件非常痛苦的

    2024年04月23日
    瀏覽(30)
  • springboot整合多數(shù)據(jù)源的配置以及動態(tài)切換數(shù)據(jù)源,注解切換數(shù)據(jù)源

    springboot整合多數(shù)據(jù)源的配置以及動態(tài)切換數(shù)據(jù)源,注解切換數(shù)據(jù)源

    在許多應(yīng)用程序中,可能需要使用多個數(shù)據(jù)庫或數(shù)據(jù)源來處理不同的業(yè)務(wù)需求。Spring Boot提供了簡便的方式來配置和使用多數(shù)據(jù)源,使開發(fā)人員能夠輕松處理多個數(shù)據(jù)庫連接。如果你的項目中可能需要隨時切換數(shù)據(jù)源的話,那我這篇文章可能能幫助到你 ??:這里對于pom文件

    2024年02月10日
    瀏覽(33)
  • Grafana(二)Grafana 兩種數(shù)據(jù)源圖表展示(json-api與數(shù)據(jù)庫)

    Grafana(二)Grafana 兩種數(shù)據(jù)源圖表展示(json-api與數(shù)據(jù)庫)

    在先前的博客文章中,我們搭建了Grafana ,它是一個開源的度量分析和可視化工具,可以通過將采集的數(shù)據(jù)分析、查詢,然后進(jìn)行可視化的展示,接下來我們重點介紹如何使用它來進(jìn)行數(shù)據(jù)渲染圖表展示 Docker安裝Grafana-CSDN博客 文章瀏覽閱讀1.2k次,點贊25次,收藏22次。分析上

    2024年01月17日
    瀏覽(21)
  • springboot配置數(shù)據(jù)源

    Spring Framework 為 SQL 數(shù)據(jù)庫提供了廣泛的支持。從直接使用 JdbcTemplate 進(jìn)行 JDBC 訪問到完全的對象關(guān)系映射(object relational mapping)技術(shù),比如 Hibernate。Spring Data 提供了更多級別的功能,直接從接口創(chuàng)建的 Repository 實現(xiàn),并使用了約定從方法名生成查詢。 1、JDBC 1、創(chuàng)建項目,導(dǎo)

    2024年02月08日
    瀏覽(30)
  • 分享一些常用的數(shù)據(jù)庫結(jié)構(gòu)表和字段語句(BI系統(tǒng)數(shù)據(jù)源部分可能會用到)

    獲取該數(shù)據(jù)庫的表(表名,行數(shù),表注釋) 獲取該表的字段信息(字段名,字段類型,字段注釋) 獲取該數(shù)據(jù)庫的表(表名,行數(shù),表注釋) 獲取該表的字段信息(字段名,字段類型,字段注釋) 獲取該數(shù)據(jù)庫的表(表名,行數(shù),表注釋) 獲取該表的字段信息(字段名,

    2024年02月15日
    瀏覽(26)
  • springboot之多數(shù)據(jù)源配置

    springboot之多數(shù)據(jù)源配置

    實際開發(fā)中,進(jìn)場可能遇到在一個引用中可能需要訪問多個數(shù)據(jù)庫的情況,以下是兩種典型場景: 數(shù)據(jù)分布在不同的數(shù)據(jù)庫匯總,數(shù)據(jù)庫拆了,應(yīng)用沒拆。一個公司多個子項目,各用各的數(shù)據(jù)庫,涉及數(shù)據(jù)共享。。。。 為了解決數(shù)據(jù)庫的讀性能瓶頸(讀比寫性能更高,寫鎖

    2024年02月07日
    瀏覽(26)
  • SpringBoot Redis 配置多數(shù)據(jù)源

    SpringBoot Redis 配置多數(shù)據(jù)源

    使用 RedisTemplate 支持多個 Redis 數(shù)據(jù)庫 《Redis 從入門到精通【進(jìn)階篇】之Lua腳本詳解》 《Redis 從入門到精通【實踐篇】SpringBoot Redis 配置多數(shù)據(jù)源》 《Redis 從入門到精通【進(jìn)階篇】三分鐘了解Redis地理位置數(shù)據(jù)結(jié)構(gòu)GeoHash》 《Redis 從入門到精通【進(jìn)階篇】一文學(xué)會Lua腳本》 《

    2024年02月16日
    瀏覽(23)
  • Springboot+Druid配置多數(shù)據(jù)源

    Spring的多數(shù)據(jù)源支持—AbstractRoutingDataSource,AbstractRoutingDataSource定義了抽象的determineCurrentLookupKey方法,子類實現(xiàn)此方法,來確定要使用的數(shù)據(jù)源 Druid 實現(xiàn)多數(shù)據(jù)源支持,核心是Overwrite AbstractRoutingDataSource 的 determineCurrentLookupKey 方法 以springboot框架為基礎(chǔ)使用aop注解的方式依賴

    2024年02月11日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包