在现代软件开发中,尤其是在处理复杂业务逻辑时,经常需要从多个数据源中读取或写入数据。Spring Boot作为一个流行的Java框架,提供了强大的数据源配置功能,使得动态数据源切换变得相对简单。本文将详细介绍如何在Spring Boot应用中实现动态数据源切换。
准备工作
在开始实现动态数据源切换之前,我们需要做一些准备工作:
-
创建Spring Boot项目:
- 可以使用Spring Initializr快速生成项目骨架。在创建项目时,选择合适的JDK版本、项目构建工具(如Maven或Gradle)以及项目元数据(如项目名称、描述、包名等)。
-
添加依赖:
-
在项目的
pom.xml
文件中添加必要的依赖。例如:xml<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>
-
实现动态数据源切换
接下来,我们将介绍如何实现动态数据源切换。主要分为以下几个步骤:
-
配置数据源:
-
在
application.properties
或application.yml
文件中配置多个数据源。例如:yamlspring: datasource: primary: url: jdbc:mysql://localhost:3306/primary_db username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver secondary: url: jdbc:mysql://localhost:3306/secondary_db username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver
-
-
定义数据源配置类:
-
创建一个数据源配置类,用于配置多数据源。例如:
javapackage cn.juwatech.config; import com.zaxxer.hikari.HikariDataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; @Configuration public class DataSourceConfig { @Primary @Bean(name = "primaryDataSource") @ConfigurationProperties("spring.datasource.primary") public HikariDataSource primaryDataSource() { return new HikariDataSource(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties("spring.datasource.secondary") public HikariDataSource secondaryDataSource() { return new HikariDataSource(); } }
-
-
定义数据源上下文和切换器:
-
创建一个数据源上下文类,用于存储当前线程使用的数据源。例如:
javapackage cn.juwatech.datasource; public class DataSourceContextHolder { private static final ThreadLocal<String> contextHolder = new ThreadLocal<>(); public static void setDataSource(String dataSource) { contextHolder.set(dataSource); } public static String getDataSource() { return contextHolder.get(); } public static void clearDataSource() { contextHolder.remove(); } }
-
创建一个数据源切换器,用于动态切换数据源。例如:
javapackage cn.juwatech.datasource; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; public class DynamicRoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); } }
-
-
配置动态数据源:
-
在配置类中使用动态数据源。例如:
javapackage cn.juwatech.config; import cn.juwatech.datasource.DynamicRoutingDataSource; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; @Configuration public class DataSourceConfig { @Primary @Bean(name = "primaryDataSource") @ConfigurationProperties("spring.datasource.primary") public DataSource primaryDataSource() { return new HikariDataSource(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties("spring.datasource.secondary") public DataSource secondaryDataSource() { return new HikariDataSource(); } @Bean public DataSource dataSource() { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("primaryDataSource", primaryDataSource()); targetDataSources.put("secondaryDataSource", secondaryDataSource()); DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource(); routingDataSource.setDefaultTargetDataSource(primaryDataSource()); routingDataSource.setTargetDataSources(targetDataSources); return routingDataSource; } }
-
使用动态数据源
在业务代码中,根据业务逻辑和条件设置ThreadLocal
中的数据源信息。例如:
java
DataSourceContextHolder.setDataSource("secondaryDataSource"); // 设置当前线程的数据源为secondary
在数据访问层(如DAO),使用动态数据源来获取数据源并执行查询。MyBatis-Plus会根据ThreadLocal
中的数据源信息来决定从哪个数据源中获取数据。当业务逻辑执行完成后,记得清除ThreadLocal
中的数据源信息,以避免对其他线程造成影响。
总结
通过上述步骤,我们实现了在Spring Boot应用中动态切换数据源的功能。这不仅可以提高应用程序的灵活性和可扩展性,还能满足复杂业务逻辑下的数据处理需求。在实际开发中,可以根据具体业务需求进行进一步的优化和扩展。