最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Springboot動態(tài)切換數(shù)據源的具體實現(xiàn)與原理分析

 更新時間:2021年12月12日 15:43:01   作者:既然頭發(fā)留不住  
目前有個需求,需要使用不同的數(shù)據源,例如某業(yè)務要用A數(shù)據源,另一個業(yè)務要用B數(shù)據源,所以下面這篇文章主要給大家介紹了關于Springboot動態(tài)切換數(shù)據源的具體實現(xiàn)與原理分析,需要的朋友可以參考下

前言

在springboot項目中只需一句代碼即可實現(xiàn)多個數(shù)據源之間的切換:

// 切換sqlserver數(shù)據源:
DataSourceContextHolder.setDataBaseType(DataSourceEnum.SQLSERVER_DATASOURCE);
......
// 切換mysql數(shù)據源    
DataSourceContextHolder.setDataBaseType(DataSourceEnum.MYSQL_DATASOURCE);

具體實現(xiàn):

本實例基于springboot2.5+版本實現(xiàn)。

1.配置數(shù)據源:

在配置文件中配置多個數(shù)據源的連接信息,用不同的前綴作為區(qū)別:

# sqlserver數(shù)據源1:前綴為:spring.datasource.sqlserver
spring.datasource.sqlserver.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.sqlserver.jdbc-url=jdbc:sqlserver://localhost:1433;DatabaseName=test
spring.datasource.sqlserver.username=sa
spring.datasource.sqlserver.password=sa
# mysql數(shù)據源1:前綴為:spring.datasource.mysql
spring.datasource.mysql.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.mysql.jdbc-url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true
spring.datasource.mysql.username=root
spring.datasource.mysql.password=root
# sqlLite數(shù)據源1:前綴為:spring.datasource.sqlite
spring.datasource.sqlite.driver-class-name=org.sqlite.JDBC
spring.datasource.sqlite.jdbc-url=jdbc:sqlite:D://sqllite//test.db
spring.datasource.sqlite.username=
spring.datasource.sqlite.password=
# sqlserver數(shù)據源2:前綴為:spring.datasource.sqlserver2
spring.datasource.sqlserver2.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.sqlserver2.jdbc-url=jdbc:sqlserver://localhost;DatabaseName=test1
spring.datasource.sqlserver2.username=sa
spring.datasource.sqlserver2.password=sa
# 配置數(shù)據庫連接池信息
spring.datasource.hikari.maximum-pool-size=32
spring.datasource.hikari.minimum-idle=16

2.新建枚舉類DataSourceEnum,有幾個數(shù)據源對應設置幾個枚舉類。

public enum DataSourceEnum {
    MYSQL_DATASOURCE,
    SQLSERVER_DATASOURCE,
    SQLSERVER2_DATASOURCE,
    SQLLITE_DATASOURCE
}

3.新建數(shù)據庫切換工具類DataSourceContextHolder,這里通過ThreadLocal類型的變量來存儲當前數(shù)據源枚舉類,同時能夠保證線程安全。

public class DataSourceContextHolder {

    /**
     * 通過ThreadLocal保證線程安全
     */
    private static final ThreadLocal<DataSourceEnum> contextHolder = new ThreadLocal<>();

    /**
     * 設置數(shù)據源變量
     * @param dataSourceEnum 數(shù)據源變量
     */
    public static void setDataBaseType(DataSourceEnum dataSourceEnum) {
        System.out.println("修改數(shù)據源為:" + dataSourceEnum);
        contextHolder.set(dataSourceEnum);
    }

    /**
     * 獲取數(shù)據源變量
     * @return 數(shù)據源變量
     */
    public static DataSourceEnum getDataBaseType() {
        DataSourceEnum dataSourceEnum = contextHolder.get() == null ? DataSourceEnum.MYSQL_DATASOURCE : contextHolder.get();
        System.out.println("當前數(shù)據源的類型為:" + dataSourceEnum);
        return dataSourceEnum;
    }

    /**
     * 清空數(shù)據類型
     */
    public static void clearDataBaseType() {
        contextHolder.remove();
    }

4.新建DynamicDataSource類繼承AbstractRoutingDataSource類,并實現(xiàn)determineCurrentLookupKey方法,該方法是指定當前默認數(shù)據源的方法。

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataBaseType();
    }
}

這個類看似內容不多,但其實繼承了AbstractRoutingDataSource類是實現(xiàn)動態(tài)切換數(shù)據源的關鍵。

5.新建DataSourceConfig類用來創(chuàng)建bean的實例,其中包括各數(shù)據源的DataSource實例,DynamicDataSource實例以及跟Mybatis相關的SqlSessionFactory或Spring的JdbcTemplate實例。

@Configuration
public class DataSourceConfig {
    @Bean(name = "sqlserverDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.sqlserver")
    public DataSource getDateSource1() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "sqlserver2DataSource")
    @ConfigurationProperties(prefix = "spring.datasource.sqlserver2")
    public DataSource getDateSource11() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "mysqlDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.mysql")
    public DataSource getDateSource2() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "sqlLiteDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.sqlite")
    public DataSource getDateSource3() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "dynamicDataSource")
    public DynamicDataSource DataSource(@Qualifier("sqlserverDataSource") DataSource sqlserverDataSource,
                                        @Qualifier("sqlserver2DataSource") DataSource sqlserver2DataSource,
                                        @Qualifier("mysqlDataSource") DataSource mysqlDataSource,
                                        @Qualifier("sqlLiteDataSource") DataSource sqlLiteDataSource) {
        //配置多數(shù)據源
        Map<Object, Object> targetDataSource = new HashMap<>();
        targetDataSource.put(DataSourceEnum.SQLSERVER_DATASOURCE, sqlserverDataSource);
        targetDataSource.put(DataSourceEnum.MYSQL_DATASOURCE, mysqlDataSource);
        targetDataSource.put(DataSourceEnum.SQLLITE_DATASOURCE, sqlLiteDataSource);
        targetDataSource.put(DataSourceEnum.SQLSERVER2_DATASOURCE, sqlserver2DataSource);
        DynamicDataSource dataSource = new DynamicDataSource();
        //多數(shù)據源
        dataSource.setTargetDataSources(targetDataSource);
        //默認數(shù)據源
        dataSource.setDefaultTargetDataSource(sqlserverDataSource);
        return dataSource;
    }
    @Bean(name = "SqlSessionFactory")
    public SqlSessionFactory test1SqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        return bean.getObject();
    }

    @Bean(name = "JdbcTemplate")
    public JdbcTemplate test1JdbcTemplate(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
        return new JdbcTemplate(dynamicDataSource);
    }
}

這樣就把我們切換數(shù)據庫鎖需要的bean全部交給spring容器中了,使用時直接通過DataSourceContextHolder.setDataBaseType(DataSourceEnum dataSourceEnum);這個方法指定數(shù)據源對應的枚舉類即可。

原理分析:

其實我們新建數(shù)據庫連接的時候也是通過DataSource來獲取連接的,這里的AbstractRoutingDataSource也是通過了DataSource中的getConnection方法來獲取連接的。

這個類里維護了兩個Map來存儲數(shù)據庫連接信息:

@Nullable
private Map<Object, Object> targetDataSources; 

@Nullable
private Object defaultTargetDataSource;

private boolean lenientFallback = true;

private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();

@Nullable
private Map<Object, DataSource> resolvedDataSources;

@Nullable
private DataSource resolvedDefaultDataSource;

下面對上面的幾個屬性進行說明:

其中第一個targetDataSources是一個Map對象,在我們上面第五步創(chuàng)建DynamicDataSource實例的時候將多個數(shù)據源的DataSource類,放入到這個Map中去,這里的Key是枚舉類,values就是DataSource類。

第二個defaultTargetDataSource是默認的數(shù)據源,就是DynamicDataSource中唯一重寫的方法來給這個對象賦值的。

第三個lenientFallback是一個標識,是當指定數(shù)據源不存在的時候是否采用默認數(shù)據源,默認是true,設置為false之后如果找不到指定數(shù)據源將會返回null.

第四個dataSourceLookup是用來解析指定的數(shù)據源對象為DataSource實例的。默認是JndiDataSourceLookup實例,繼承自DataSourceLookup接口。

第五個resolvedDataSources也是一個Map對象,這里是存放指定數(shù)據源解析后的DataSource對象。

第六個resolvedDefaultDataSource是默認的解析后的DataSource數(shù)據源對象上面的getConnection方法就是從這個變量中拿到DataSource實例并獲取連接的。

總結

相關文章

  • Java中使用HttpPost發(fā)送form格式的請求實現(xiàn)代碼

    Java中使用HttpPost發(fā)送form格式的請求實現(xiàn)代碼

    在Java中使用HttpPost發(fā)送form格式的請求,可以使用Apache HttpClient庫來實現(xiàn),這篇文章主要介紹了Java中使用HttpPost發(fā)送form格式的請求,本文給大家展示示例代碼,需要的朋友可以參考下
    2023-08-08
  • Java線程關閉的3種方法

    Java線程關閉的3種方法

    這篇文章介紹了Java線程關閉的3種方法,有需要的朋友可以參考一下
    2013-10-10
  • Springboot轉發(fā)重定向實現(xiàn)方式解析

    Springboot轉發(fā)重定向實現(xiàn)方式解析

    這篇文章主要介紹了springboot轉發(fā)重定向實現(xiàn)方式解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • 你真的會使用Java的方法引用嗎

    你真的會使用Java的方法引用嗎

    這篇文章主要給大家介紹了關于Java方法引用的相關資料,方法引用是Java8的新特性,方法引用其實也離不開Lambda表達式,本文通過示例代碼介紹的很詳細,需要的朋友可以參考下
    2021-08-08
  • Spring如何解決循環(huán)依賴的問題

    Spring如何解決循環(huán)依賴的問題

    這篇文章主要介紹了Spring是如何解決循環(huán)依賴的問題,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • Java設計模式之備忘錄模式

    Java設計模式之備忘錄模式

    這篇文章介紹了Java設計模式之備忘錄模式,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-10-10
  • Java中的SpringAOP、代理模式、常用AspectJ注解詳解

    Java中的SpringAOP、代理模式、常用AspectJ注解詳解

    這篇文章主要介紹了Java中的SpringAOP、代理模式、常用AspectJ注解詳解,Spring提供了面向切面編程的豐富支持,允許通過分離應用的業(yè)務邏輯與系統(tǒng)級服務,例如審計和事務管理進行內聚性的開發(fā),需要的朋友可以參考下
    2023-09-09
  • 基于maven的springboot的"過時"用法解析

    基于maven的springboot的"過時"用法解析

    這篇文章主要為大家介紹了基于maven的springboot"過時"用法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • 如何讓Jackson JSON生成的數(shù)據包含的中文以unicode方式編碼

    如何讓Jackson JSON生成的數(shù)據包含的中文以unicode方式編碼

    這篇文章主要介紹了如何讓Jackson JSON生成的數(shù)據包含的中文以unicode方式編碼。需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • SpringBoot使用JSP作為視圖模板的方法

    SpringBoot使用JSP作為視圖模板的方法

    這篇文章主要介紹了SpringBoot使用JSP作為視圖模板的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08

最新評論

化德县| 平原县| 华宁县| 博客| 海城市| 土默特右旗| 天津市| 商洛市| 方正县| 奉贤区| 涿鹿县| 寿宁县| 铅山县| 博罗县| 金乡县| 龙州县| 抚宁县| 泽普县| 沭阳县| 二连浩特市| 赤水市| 太和县| 微山县| 长阳| 澳门| 博白县| 顺平县| 芦山县| 中阳县| 平远县| 富锦市| 云阳县| 博客| 四子王旗| 申扎县| 精河县| 马山县| 赣州市| 田阳县| 门源| 新化县|