欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot中Druid連接池與多數(shù)據(jù)源切換的方法

 更新時(shí)間:2024年11月15日 09:37:54   作者:碼到三十五  
微服務(wù)架構(gòu)中多數(shù)據(jù)源切換是個(gè)常見(jiàn)的需求,Spring Boot 提供了強(qiáng)大的支持來(lái)簡(jiǎn)化這一過(guò)程.本文給大家介紹了SpringBoot中Druid連接池與多數(shù)據(jù)源切換的方法,需要的朋友可以參考下

多數(shù)據(jù)源切換原理

多數(shù)據(jù)源切換的原理主要基于 Spring 的 AbstractRoutingDataSource 類(lèi)。AbstractRoutingDataSource 類(lèi)允許根據(jù)運(yùn)行時(shí)上下文動(dòng)態(tài)選擇數(shù)據(jù)源。其核心在于實(shí)現(xiàn) determineCurrentLookupKey 方法,該方法決定當(dāng)前操作使用哪個(gè)數(shù)據(jù)源。 AbstractRoutingDataSource 實(shí)現(xiàn)多數(shù)據(jù)源切換的原理:

1. 數(shù)據(jù)源映射

  • AbstractRoutingDataSource 內(nèi)部維護(hù)了一個(gè)映射(Map),用于存儲(chǔ)數(shù)據(jù)源標(biāo)識(shí)(key)和對(duì)應(yīng)的數(shù)據(jù)源實(shí)例(value)。這個(gè)映射允許根據(jù)數(shù)據(jù)源標(biāo)識(shí)快速查找和獲取對(duì)應(yīng)的數(shù)據(jù)源。

2. 數(shù)據(jù)源標(biāo)識(shí)的確定

  • AbstractRoutingDataSource 提供了一個(gè)抽象方法 determineCurrentLookupKey(),該方法用于確定當(dāng)前需要使用的數(shù)據(jù)源標(biāo)識(shí)。這個(gè)方法需要由子類(lèi)實(shí)現(xiàn),以返回當(dāng)前線程或請(qǐng)求應(yīng)該使用的數(shù)據(jù)源標(biāo)識(shí)。

3. 數(shù)據(jù)源的選擇與連接獲取

  • 當(dāng)應(yīng)用程序需要獲取數(shù)據(jù)庫(kù)連接時(shí),AbstractRoutingDataSource 的 getConnection() 方法會(huì)被調(diào)用。這個(gè)方法首先調(diào)用 determineCurrentLookupKey() 方法來(lái)獲取當(dāng)前的數(shù)據(jù)源標(biāo)識(shí),然后根據(jù)這個(gè)標(biāo)識(shí)從內(nèi)部映射中查找對(duì)應(yīng)的數(shù)據(jù)源。
  • 一旦找到了對(duì)應(yīng)的數(shù)據(jù)源,AbstractRoutingDataSource 就會(huì)調(diào)用該數(shù)據(jù)源的 getConnection() 方法來(lái)獲取實(shí)際的數(shù)據(jù)庫(kù)連接,并將這個(gè)連接返回給應(yīng)用程序。

4. 數(shù)據(jù)源切換的實(shí)現(xiàn)

  • 為了實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)切換,通常會(huì)在子類(lèi)中重寫(xiě) determineCurrentLookupKey() 方法,并根據(jù)當(dāng)前的上下文(如線程變量)來(lái)確定返回的數(shù)據(jù)源標(biāo)識(shí)。
  • 此外,通常會(huì)使用 ThreadLocal 來(lái)存儲(chǔ)每個(gè)線程的數(shù)據(jù)源標(biāo)識(shí),這樣每個(gè)線程都可以獨(dú)立地切換數(shù)據(jù)源而不會(huì)互相干擾。

實(shí)現(xiàn)步驟

1. 依賴(lài)

引入 MySQL 和 Druid 的依賴(lài)

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.2.6</version>
</dependency>

2. 配置數(shù)據(jù)源

在 application.yml 文件中配置多個(gè)數(shù)據(jù)源。

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      datasource1:
        url: jdbc:mysql://localhost:3306/master_db
        username: root
        password: password
        initial-size: 5
        min-idle: 5
        max-active: 20
        max-wait: 60000
      datasource2:
        url: jdbc:mysql://localhost:3306/slave_db
        username: root
        password: password
        initial-size: 5
        min-idle: 5
        max-active: 20
        max-wait: 60000

3. 創(chuàng)建數(shù)據(jù)源配置類(lèi)

創(chuàng)建一個(gè)配置類(lèi)來(lái)定義數(shù)據(jù)源 Bean。

@Configuration
public class DataSourceConfig {

    @Bean
    @ConditionalOnProperty(prefix = "spring.datasource.druid", name = "datasource1")
    @ConfigurationProperties(prefix = "spring.datasource.druid.datasource1")
    public DataSource dataSource1() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConditionalOnProperty(prefix = "spring.datasource.druid", name = "datasource2")
    @ConfigurationProperties(prefix = "spring.datasource.druid.datasource2")
    public DataSource dataSource2() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(dataSource1());
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("dataSource1", dataSource1());
        targetDataSources.put("dataSource2", dataSource2());
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

4. 實(shí)現(xiàn) AbstractRoutingDataSource

創(chuàng)建一個(gè)繼承自 AbstractRoutingDataSource 的類(lèi),并實(shí)現(xiàn) determineCurrentLookupKey 方法。

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

5. 創(chuàng)建 DataSourceContextHolder

創(chuàng)建一個(gè)工具類(lèi)來(lái)保存當(dāng)前線程的數(shù)據(jù)源信息。

public class DataSourceContextHolder {

    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDataSource(String dataSource) {
        CONTEXT_HOLDER.set(dataSource);
    }

    public static String getDataSource() {
        return CONTEXT_HOLDER.get();
    }

    public static void clearDataSource() {
        CONTEXT_HOLDER.remove();
    }
}

6. AOP動(dòng)態(tài)切換數(shù)據(jù)源

使用 AOP 在方法執(zhí)行前后切換數(shù)據(jù)源。

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceAspect {
	// 方法或者類(lèi)上的橫切點(diǎn)
    @Pointcut("@annotation(dataSource) || @within(dataSource)")
    public void dataSourcePointcut(DataSource dataSource) {}

    @Before("dataSourcePointcut(dataSource)")
    public void switchDataSource(JoinPoint joinPoint, DataSource dataSource) {
        // 從注解中獲取數(shù)據(jù)源標(biāo)識(shí)
        String dataSourceKey = dataSource.value();
        // 切換到指定的數(shù)據(jù)源
        DataSourceContextHolder.setDataSourceType(dataSourceKey);
    }

    @AfterReturning(pointcut = "dataSourcePointcut(dataSource)", returning = "result")
    public void restoreDataSource(JoinPoint joinPoint, DataSource dataSource, Object result) {
        // 恢復(fù)默認(rèn)數(shù)據(jù)源(可選)
        DataSourceContextHolder.clearDataSourceType();
    }
}

/**
* 自定義注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {

    String value() default "dataSource1";
}

7. 使用自定義注解

在需要切換數(shù)據(jù)源的方法上使用自定義注解。

注意

  • 數(shù)據(jù)源切換的邏輯應(yīng)該盡可能簡(jiǎn)單和高效,以避免對(duì)應(yīng)用程序性能產(chǎn)生負(fù)面影響。
  • 在切換數(shù)據(jù)源時(shí),需要注意事務(wù)管理的問(wèn)題,確保在同一個(gè)事務(wù)中只使用同一個(gè)數(shù)據(jù)源。

到此這篇關(guān)于SpringBoot中Druid連接池與多數(shù)據(jù)源切換的方法的文章就介紹到這了,更多相關(guān)SpringBoot Druid與數(shù)據(jù)源切換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論