开发者

SpringBoot中Druid连接池与多数据源切换的方法

目录
  • 多数据源切换原理
    • 1. 数据源映射
    • 2. 数据源标识的确定
    • 3. 数据源的选择与连接获取
    • 4. 数据源切换的实现
  • 实现步骤
    • 1. 依赖
    • 2. 配置数据源
    • 3. 创建数据源配置类
    • 4. 实现 AbstractRoutingDataSource
    • 5. 创建 DataSourceContextHolder
    • 6. AOP动态切换数据源
    • 7. 使用自定义注解
  • 注意

    多数据源切换原理

    多数据源切换的原理主要基于 Spring 的 AbstractRoutingDataSource 类。AbstractRoutingDataSource 类允许根据运行时上下文动态选择数据源。其核心在于实现 determineCurrentLookupKey 方法,该方法决定当前操作使用哪个数据源。 AbstractRoutingDataSource 实现多数据源切换的原理:

    1. 数据源映射

    • AbstractRoutingDataSource 内部维护了一个映射(Map),用于存储数据源标识(kephpy)和对应的数据源实例(value)。这个映射允许根据数据源标识快速查找和获取对应的数据源。

    2. 数据源标识的确定

    • AbstractRoutingDataSource 提供了一个抽象方法 determineCurrentLookupKey(),该方法用于确定当前需要使用的数据源标识。这个方法需要由子类实现,以返回当前线程或请求应该使用的数据源标识。

    3. 数据源的选择与连接获取

    • 当应用程序需要获取数据库连接时,AbstractRoutingDataSource 的 getConnection() 方法会被调用。这个方法首先调用 determineCurrentLookupKey() 方法来获取当前的数据源标识,然后根据这个标识从内部映射中查找对应的数据源。
    • 一旦找到了对应的数据源,AbstractRoutingDataSource 就会调用该数据源的 getConnection() 方法来获取实际的数据库连接,并将这个连接返回给应用程序。

    4. 数据源切换的实现

    • 为了实现数据源的动态切换,通常会在子类中重写 determineCurrentLookupKey() 方法,并根据当前的上下文(如线程变量)来确定返回的数据源标识。
    • 此外,通常会使用 ThreadLocal 来存储每个线程的数据源标识,这样每个线程都可以独立地切换数据源而不会互相干扰。

    实现步骤

    1. 依赖

    引入 mysql 和 Druid 的依赖

    <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. 配置数据源

    在 application.yml 文件中配置多个数据源。

    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. 创建数据源配置类

    创建一个配置类来定义数据源 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 DruidDataSojsurceBuilder.create().build();
        }
    
        @Bean
        @Primary
        public DataSource dynamicDataSource() {
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            dynamicDataSource.setDefaultTargetDaandroidtaSource(dataSource1());
            Map<Object, Object> targetDataSources = new HashMap<>();
            targetDataSources.put("dataSource1", dataSource1());
            targetDataSources.put("dataSource2", dataSource2());
            dynamicDataSource.setTargetDataSources(targetDataSources);
            return dynamicDataSource;
        }
    }
    

    4. 实现 AbstractRoutingDataSource

    创建一个继承自 AbstractRoutingDataSource 的类,并实现 determineCurrentLookupKey 方法。

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

    5. 创建 DataSourceContextHolder

    创建一个工具类来保存当前线程的数据源信息。

    public class DataSourceContextHolder {
    
        private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
    
        public static pythonvoid setDataSource(String dataSource) {
            CONTEXT_HOLDER.set(dataSource);
        }
    
        public static String getDataSource() {
            return CONTEXT_HOLDER.get();
        }
    
        public static void clearDataSource() {
            CONTEXT_HOLDER.remove();
        }
    }
    

    6. AOP动态切换数据源

    使用 AOP 在方法执行前后切换数据源。

    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 {
    	// 方法或者类上的横切点
        @Pointcut("@annotation(dataSource) || @within(dataSource)")
        public void dataSourcePointcut(DataSource dataSource) {}
    
        @Before("dataSourcePointcut(dataSource)")
        public void switchDataSource(JoinPoint joinPoint, DataSource dataSource) {
            // 从注解中获取数据源标识
            String dataSourceKey = dataSource.value();
            // 切换到指定的数据源
            DataSourceContextHolder.setDataSourceType(dataSourceKey);
        }
    
        @AfterReturning(pointcut = "dataSourcePointcut(dataSource)", returning = "result")
        public void restoreDataSource(JoinPoint joinPoint, DataSource dataSource, Object result) {
            // 恢复默认数据源(可选)
            DataSourceContextHolder.clearDataSourceType();
        }
    }
    
    /**
    * 自定义注解
    */
    @Target({ElementType.METHOD, ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DataSource {
    
        String value() default "dataSource1";
    }
    
    

    7. 使用自定义注解

    在需要切换数据源的方法上使用自定义注解。

    注意

    • 数据源切换的逻辑应该尽可能简单和高效,以避免对应用程序性能产生负面影响。
    • 在切换数据源时,需要注意事务管理的问题,确保在同一个事务中只使用同一个数据源。

    到此这篇关于SpringBoot中Druid连接池与多数据源切换的方法的文章就介绍到这了,更多相关SpringBoot Druid与数据源切换内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!

    0

    上一篇:

    下一篇:

    精彩评论

    暂无评论...
    验证码 换一张
    取 消

    最新开发

    开发排行榜