在SpringBoot项目中动态切换数据源和数据库的详细步骤

 更新时间:2025年08月06日 09:46:44   作者:喵手  
在许多企业级应用中,可能需要根据不同的业务需求来切换不同的数据库,如读写分离、分库分表等场景,Spring Boot 提供了灵活的数据源配置方式,本文将介绍如何在 Spring Boot 项目中实现动态切换数据源和数据库的方案,需要的朋友可以参考下

前言

在许多企业级应用中,可能需要根据不同的业务需求来切换不同的数据库,如读写分离、分库分表等场景。Spring Boot 提供了灵活的数据源配置方式,可以通过动态切换数据源来实现这些需求。

本文将介绍如何在 Spring Boot 项目中实现动态切换数据源和数据库的方案。我们将使用 Spring 的 AbstractRoutingDataSource 来实现动态切换数据源。

步骤一:引入依赖

首先,确保 Spring Boot 项目引入了以下依赖,主要包括 Spring Data JPA 和 MySQL 驱动(如果使用 MySQL 数据库)。在 pom.xml 文件中添加这些依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId> <!-- 使用 HikariCP 作为连接池 -->
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

步骤二:配置多个数据源

application.propertiesapplication.yml 中配置多个数据源,假设我们配置了主数据源和从数据源。

application.properties 示例:

# 主数据源配置
spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary_db
spring.datasource.primary.username=root
spring.datasource.primary.password=root_password
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.primary.hikari.maximum-pool-size=10

# 从数据源配置
spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary_db
spring.datasource.secondary.username=root
spring.datasource.secondary.password=root_password
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.secondary.hikari.maximum-pool-size=10

步骤三:自定义动态数据源

Spring Boot 默认的配置是固定的单一数据源,但我们可以通过自定义 AbstractRoutingDataSource 来实现动态数据源切换。

1. 自定义 DynamicDataSource 类

AbstractRoutingDataSource 是 Spring 提供的一个用于路由到不同数据源的抽象类,我们继承该类并重写 determineCurrentLookupKey() 方法,根据当前线程或请求上下文来决定使用哪个数据源。

public class DynamicDataSource extends AbstractRoutingDataSource {

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

2. 定义 DataSourceContextHolder 类

为了实现线程安全地存储当前数据源的上下文,我们使用 ThreadLocal 来保存当前线程的数据源标识。

public class DataSourceContextHolder {

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

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

    public static String getDataSourceType() {
        return contextHolder.get();
    }

    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

3. 配置动态数据源

在配置类中,将多个数据源(如主数据库和从数据库)与 DynamicDataSource 关联,并将 DynamicDataSource 设置为 Spring 管理的数据源。

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class DataSourceConfig {

    @Primary
    @Bean
    public DynamicDataSource dynamicDataSource(
        @Qualifier("primaryDataSource") DataSource primaryDataSource,
        @Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("primary", primaryDataSource);
        targetDataSources.put("secondary", secondaryDataSource);

        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        dynamicDataSource.setDefaultTargetDataSource(primaryDataSource);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        return DataSourceBuilder.create().build();
    }
}

步骤四:切换数据源

为了动态切换数据源,我们可以在需要切换数据源的地方设置数据源类型(如读写分离、业务模块分库等)。

1. 在服务层切换数据源

在服务方法中,我们可以通过 DataSourceContextHolder.setDataSourceType("primary")DataSourceContextHolder.setDataSourceType("secondary") 来切换数据源。

@Service
public class DataService {

    // 使用主数据源
    public void usePrimaryDataSource() {
        DataSourceContextHolder.setDataSourceType("primary");
        // 执行主数据库相关操作
    }

    // 使用从数据源
    public void useSecondaryDataSource() {
        DataSourceContextHolder.setDataSourceType("secondary");
        // 执行从数据库相关操作
    }

    // 清除数据源设置
    public void clearDataSource() {
        DataSourceContextHolder.clearDataSourceType();
    }
}

2. 在控制器层切换数据源

在控制器层中,可以根据请求的不同选择使用不同的数据源。

@RestController
@RequestMapping("/data")
public class DataController {

    @Autowired
    private DataService dataService;

    @GetMapping("/usePrimary")
    public String usePrimaryDataSource() {
        dataService.usePrimaryDataSource();
        return "Using Primary DataSource";
    }

    @GetMapping("/useSecondary")
    public String useSecondaryDataSource() {
        dataService.useSecondaryDataSource();
        return "Using Secondary DataSource";
    }
}

步骤五:使用AOP统一切换数据源

为了更优雅地切换数据源并解耦,我们可以通过 AOP(面向切面编程)来统一处理数据源切换。我们可以创建一个自定义注解来标识哪些方法需要切换数据源。

1. 自定义注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceSwitch {
    String value() default "primary"; // 默认使用主数据源
}

2. 切面类实现

创建切面类,在方法执行前根据注解指定的数据源值来切换数据源。

@Aspect
@Component
public class DataSourceAspect {

    @Before("@annotation(dataSourceSwitch)")
    public void switchDataSource(DataSourceSwitch dataSourceSwitch) {
        String dataSourceType = dataSourceSwitch.value();
        DataSourceContextHolder.setDataSourceType(dataSourceType);
    }

    @After("@annotation(dataSourceSwitch)")
    public void clearDataSource(DataSourceSwitch dataSourceSwitch) {
        DataSourceContextHolder.clearDataSourceType();
    }
}

3. 使用注解切换数据源

@Service
public class DataService {

    @DataSourceSwitch("primary")
    public void usePrimaryDataSource() {
        // 使用主数据源
    }

    @DataSourceSwitch("secondary")
    public void useSecondaryDataSource() {
        // 使用从数据源
    }
}

总结

通过在 Spring Boot 中实现动态数据源切换,我们可以灵活地管理不同数据库的使用,满足不同业务场景的需求。无论是简单的读写分离、分库还是更复杂的业务需求,都可以通过动态切换数据源来完成。通过结合 AOP 和注解,我们可以更加优雅地管理和切换数据源,避免了硬编码和重复代码的情况,提升了代码的可维护性和扩展性。

以上就是在SpringBoot项目中动态切换数据源和数据库的详细步骤的详细内容,更多关于SpringBoot动态切换数据源和数据库的资料请关注脚本之家其它相关文章!

相关文章

  • springboot3整合knife4j超详细教程(不带swagger2玩)

    springboot3整合knife4j超详细教程(不带swagger2玩)

    本文详细介绍了如何在Spring Boot 3项目中整合Knife4j,并提供了配置文件的详细说明和常用注解的使用方法,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • 基于ZooKeeper实现队列源码

    基于ZooKeeper实现队列源码

    这篇文章主要介绍了基于ZooKeeper实现队列源码的相关内容,包括其实现原理和应用场景,以及对队列的简单介绍,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09
  • Spring Security学习之rememberMe自动登录的实现

    Spring Security学习之rememberMe自动登录的实现

    这篇文章主要给大家介绍了关于Spring Security学习之rememberMe自动登录的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2020-06-06
  • spring mvc利用ajax向controller传递对象的方法示例

    spring mvc利用ajax向controller传递对象的方法示例

    这篇文章主要给大家介绍了关于spring mvc利用ajax向controller传递对象的相关资料,文中通过示例代码将步骤介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来跟着小编一起学习学习吧。
    2017-07-07
  • Java毕业设计实战项目之仓库管理系统的实现流程

    Java毕业设计实战项目之仓库管理系统的实现流程

    这是一个使用了java+SSM+Maven+Bootstrap+mysql开发的仓库管理系统,是一个毕业设计的实战练习,具有一个仓库管理系统该有的所有功能,感兴趣的朋友快来看看吧
    2022-01-01
  • Java为啥能跨平台(原因解析)JDK/JRE/JVM的关系说明

    Java为啥能跨平台(原因解析)JDK/JRE/JVM的关系说明

    JVM是Java虚拟机,是Java程序的运行环境,Java的跨平台特性是由于JVM的适配性设计,JDK、JRE、JVM三者的关系是JDK> JRE > JVM,本文介绍Java为啥能跨平台,JDK/JRE/JVM的关系说明,感兴趣的朋友一起看看吧
    2025-12-12
  • JAVA线上常见问题排查手段汇总

    JAVA线上常见问题排查手段汇总

    这篇文章主要介绍了JAVA线上常见问题排查手段汇总,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • @Async导致controller 404及失效原因解决分析

    @Async导致controller 404及失效原因解决分析

    这篇文章主要为大家介绍了@Async导致controller 404失效问题解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • 全方位讲解Java的面向对象编程思想

    全方位讲解Java的面向对象编程思想

    这篇文章主要介绍了Java的面相对象编程思想,包括类对象方法和封装继承多态等各个方面的OOP基本要素,非常推荐,需要的朋友可以参考下
    2016-01-01
  • MyBatis-Plus集成Druid环境搭建的详细教程

    MyBatis-Plus集成Druid环境搭建的详细教程

    这篇文章主要介绍了MyBatis-Plus集成Druid环境搭建的详细教程,需要的朋友可以参考下
    2020-08-08

最新评论