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

詳細聊聊SpringBoot中動態(tài)切換數(shù)據(jù)源的方法

 更新時間:2021年09月29日 12:58:09   作者:Nicksxs  
在大型分布式項目中,經常會出現(xiàn)多數(shù)據(jù)源的情況,下面這篇文章主要給大家介紹了關于SpringBoot中動態(tài)切換數(shù)據(jù)源的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

其實這個表示有點不太對,應該是 Druid 動態(tài)切換數(shù)據(jù)源的方法,只是應用在了 springboot 框架中,準備代碼準備了半天,之前在一次數(shù)據(jù)庫遷移中使用了,發(fā)現(xiàn) Druid 還是很強大的,用來做動態(tài)數(shù)據(jù)源切換很方便。

首先這里的場景跟我原來用的有點點區(qū)別,在項目中使用的是通過配置中心控制數(shù)據(jù)源切換,統(tǒng)一切換,而這里的例子多加了個可以根據(jù)接口注解配置

第一部分是最核心的,如何基于 Spring JDBC 和 Druid 來實現(xiàn)數(shù)據(jù)源切換,是繼承了org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource 這個類,他的determineCurrentLookupKey方法會被調用來獲得用來決定選擇那個數(shù)據(jù)源的對象,也就是 lookupKey,也可以通過這個類看到就是通過這個 lookupKey 來路由找到數(shù)據(jù)源。

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        if (DatabaseContextHolder.getDatabaseType() != null) {
            return DatabaseContextHolder.getDatabaseType().getName();
        }
        return DatabaseType.MASTER1.getName();
    }
}

而如何使用這個 lookupKey 呢,就涉及到我們的 DataSource 配置了,原來就是我們可以直接通過spring 的 jdbc 配置數(shù)據(jù)源,像這樣

現(xiàn)在我們要使用 Druid 作為數(shù)據(jù)源了,然后配置 DynamicDataSource的參數(shù),通過 key 來選擇對應的 DataSource,也就是下面配的 master1 和 master2

<bean id="master1" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close"
          p:driverClassName="com.mysql.cj.jdbc.Driver"
          p:url="${master1.demo.datasource.url}"
          p:username="${master1.demo.datasource.username}"
          p:password="${master1.demo.datasource.password}"
          p:initialSize="5"
          p:minIdle="1"
          p:maxActive="10"
          p:maxWait="60000"
          p:timeBetweenEvictionRunsMillis="60000"
          p:minEvictableIdleTimeMillis="300000"
          p:validationQuery="SELECT 'x'"
          p:testWhileIdle="true"
          p:testOnBorrow="false"
          p:testOnReturn="false"
          p:poolPreparedStatements="false"
          p:maxPoolPreparedStatementPerConnectionSize="20"
          p:connectionProperties="config.decrypt=true"
          p:filters="stat,config"/>

    <bean id="master2" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"
          destroy-method="close"
          p:driverClassName="com.mysql.cj.jdbc.Driver"
          p:url="${master2.demo.datasource.url}"
          p:username="${master2.demo.datasource.username}"
          p:password="${master2.demo.datasource.password}"
          p:initialSize="5"
          p:minIdle="1"
          p:maxActive="10"
          p:maxWait="60000"
          p:timeBetweenEvictionRunsMillis="60000"
          p:minEvictableIdleTimeMillis="300000"
          p:validationQuery="SELECT 'x'"
          p:testWhileIdle="true"
          p:testOnBorrow="false"
          p:testOnReturn="false"
          p:poolPreparedStatements="false"
          p:maxPoolPreparedStatementPerConnectionSize="20"
          p:connectionProperties="config.decrypt=true"
          p:filters="stat,config"/>

    <bean id="dataSource" class="com.nicksxs.springdemo.config.DynamicDataSource">
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <!-- master -->
                <entry key="master1" value-ref="master1"/>
                <!-- slave -->
                <entry key="master2" value-ref="master2"/>
            </map>
        </property>
        <property name="defaultTargetDataSource" ref="master1"/>
    </bean>

現(xiàn)在就要回到頭上,介紹下這個DatabaseContextHolder,這里使用了 ThreadLocal 存放這個 DatabaseType,為啥要用這個是因為前面說的我們想要讓接口層面去配置不同的數(shù)據(jù)源,要把持相互隔離不受影響,就使用了 ThreadLocal,關于它也可以看我前面寫的一篇文章聊聊傳說中的 ThreadLocal,而 DatabaseType 就是個簡單的枚舉

public class DatabaseContextHolder {
    public static final ThreadLocal<DatabaseType> databaseTypeThreadLocal = new ThreadLocal<>();

    public static DatabaseType getDatabaseType() {
        return databaseTypeThreadLocal.get();
    }

    public static void putDatabaseType(DatabaseType databaseType) {
        databaseTypeThreadLocal.set(databaseType);
    }

    public static void clearDatabaseType() {
        databaseTypeThreadLocal.remove();
    }
}
public enum DatabaseType {
    MASTER1("master1", "1"),
    MASTER2("master2", "2");

    private final String name;
    private final String value;

    DatabaseType(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public String getValue() {
        return value;
    }

    public static DatabaseType getDatabaseType(String name) {
        if (MASTER2.name.equals(name)) {
            return MASTER2;
        }
        return MASTER1;
    }
}

這邊可以看到就是通過動態(tài)地通過putDatabaseType設置lookupKey來進行數(shù)據(jù)源切換,要通過接口注解配置來進行設置的話,我們就需要一個注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
    String value();
}

這個注解可以配置在我的接口方法上,比如這樣

public interface StudentService {

    @DataSource("master1")
    public Student queryOne();

    @DataSource("master2")
    public Student queryAnother();

}

通過切面來進行數(shù)據(jù)源的設置

@Aspect
@Component
@Order(-1)
public class DataSourceAspect {

    @Pointcut("execution(* com.nicksxs.springdemo.service..*.*(..))")
    public void pointCut() {

    }


    @Before("pointCut()")
    public void before(JoinPoint point)
    {
        Object target = point.getTarget();
        System.out.println(target.toString());
        String method = point.getSignature().getName();
        System.out.println(method);
        Class<?>[] classz = target.getClass().getInterfaces();
        Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
                .getMethod().getParameterTypes();
        try {
            Method m = classz[0].getMethod(method, parameterTypes);
            System.out.println("method"+ m.getName());
            if (m.isAnnotationPresent(DataSource.class)) {
                DataSource data = m.getAnnotation(DataSource.class);
                System.out.println("dataSource:"+data.value());
                DatabaseContextHolder.putDatabaseType(DatabaseType.getDatabaseType(data.value()));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @After("pointCut()")
    public void after() {
    DatabaseContextHolder.clearDatabaseType();
    }
}

通過接口判斷是否帶有注解跟是注解的值,DatabaseType 的配置不太好,不過先忽略了,然后在切點后進行清理

這是我 master1 的數(shù)據(jù),

master2 的數(shù)據(jù)

然后跑一下簡單的 demo,

@Override
public void run(String...args) {
 LOGGER.info("run here");
 System.out.println(studentService.queryOne());
 System.out.println(studentService.queryAnother());

}

看一下運行結果

其實這個方法應用場景不止可以用來遷移數(shù)據(jù)庫,還能實現(xiàn)精細化的讀寫數(shù)據(jù)源分離之類的,算是做個簡單記錄和分享。

總結

到此這篇關于SpringBoot中動態(tài)切換數(shù)據(jù)源的文章就介紹到這了,更多相關SpringBoot動態(tài)切換數(shù)據(jù)源內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot實現(xiàn)Word轉PDF和TXT的實踐分享

    SpringBoot實現(xiàn)Word轉PDF和TXT的實踐分享

    研發(fā)工作中難免會遇到一些奇奇怪怪的需求,就比如最近,客戶提了個新需求:上傳一個WORD文檔,要求通過系統(tǒng)把該文檔轉換成PDF和TXT,所以本文給大家分享了SpringBoot實現(xiàn)Word轉PDF和TXT的實踐,感興趣的朋友可以參考下
    2024-08-08
  • 詳解Java如何優(yōu)雅的處理異常

    詳解Java如何優(yōu)雅的處理異常

    在編寫 Java 程序的過程中,有一種異常幾乎每個開發(fā)者都會遇到——空指針異常(NullPointerException),那么我們應該如何有效且優(yōu)雅的處理空指針異常呢,下面小編就來詳細介紹這個處理方案吧
    2023-08-08
  • SpringBoot如何通過Map實現(xiàn)策略模式

    SpringBoot如何通過Map實現(xiàn)策略模式

    策略模式是一種行為設計模式,它允許在運行時選擇算法的行為,在Spring框架中,我們可以利用@Resource注解和Map集合來優(yōu)雅地實現(xiàn)策略模式,這篇文章主要介紹了SpringBoot如何通過Map實現(xiàn)策略模式,需要的朋友可以參考下
    2025-03-03
  • Java必須學會的類的繼承與多態(tài)

    Java必須學會的類的繼承與多態(tài)

    這篇文章主要介紹了Java類的繼承與多態(tài)的相關資料,幫助大家更好的理解和學習Java,感興趣的朋友可以了解下
    2020-08-08
  • 深入了解java中的逃逸分析

    深入了解java中的逃逸分析

    這篇文章主要介紹了深入了解java中的逃逸分析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • Jeecg-Boot異常處理'jeecg-boot.QRTZ_LOCKS'?doesn't?exist問題

    Jeecg-Boot異常處理'jeecg-boot.QRTZ_LOCKS'?doesn'

    這篇文章主要介紹了Jeecg-Boot異常處理'jeecg-boot.QRTZ_LOCKS'?doesn't?exist問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • 百度翻譯API使用詳細教程(前端vue+后端springboot)

    百度翻譯API使用詳細教程(前端vue+后端springboot)

    這篇文章主要給大家介紹了關于百度翻譯API使用的相關資料,百度翻譯API是百度面向開發(fā)者推出的免費翻譯服務開放接口,任何第三方應用或網站都可以通過使用百度翻譯API為用戶提供實時優(yōu)質的多語言翻譯服務,需要的朋友可以參考下
    2024-02-02
  • Java遠程debug調試的操作步驟

    Java遠程debug調試的操作步驟

    日常項目中,通常我們的代碼都是部署到遠程的服務器,有時線上出現(xiàn)了問題,經常需要我們增加一些日志來排查問題,但是如果是測試環(huán)境的場景下或者我們能進行遠程調試的話,我們就可以使用遠程的Debug方式進行遠程調試,下面給大家介紹一下Java遠程debug調試的操作步驟
    2025-04-04
  • Java類加載器層次結構原理解析

    Java類加載器層次結構原理解析

    這篇文章主要介紹了Java類加載器層次結構原理解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-06-06
  • SpringMVC深入講解文件的上傳下載實現(xiàn)

    SpringMVC深入講解文件的上傳下載實現(xiàn)

    這篇文章主要為大家詳細介紹了springMVC實現(xiàn)文件上傳和下載的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-06-06

最新評論

无锡市| 鄂州市| 突泉县| 同德县| 叙永县| 高邑县| 老河口市| 章丘市| 鹿泉市| 通许县| 文成县| 潞城市| 普安县| 读书| 许昌县| 广宗县| 恩施市| 华宁县| 广西| 南昌市| 江西省| 德庆县| 芒康县| 达日县| 广西| 伊通| 正镶白旗| 资兴市| 大邑县| 蒲江县| 商城县| 海丰县| 吉安县| 嘉兴市| 苏州市| 大宁县| 千阳县| 浦县| 长泰县| 石景山区| 阳原县|