在SpringBoot項目中動態(tài)切換數(shù)據(jù)源和數(shù)據(jù)庫的詳細步驟
前言
在許多企業(yè)級應用中,可能需要根據(jù)不同的業(yè)務需求來切換不同的數(shù)據(jù)庫,如讀寫分離、分庫分表等場景。Spring Boot 提供了靈活的數(shù)據(jù)源配置方式,可以通過動態(tài)切換數(shù)據(jù)源來實現(xiàn)這些需求。
本文將介紹如何在 Spring Boot 項目中實現(xiàn)動態(tài)切換數(shù)據(jù)源和數(shù)據(jù)庫的方案。我們將使用 Spring 的 AbstractRoutingDataSource 來實現(xiàn)動態(tài)切換數(shù)據(jù)源。
步驟一:引入依賴
首先,確保 Spring Boot 項目引入了以下依賴,主要包括 Spring Data JPA 和 MySQL 驅動(如果使用 MySQL 數(shù)據(jù)庫)。在 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>
步驟二:配置多個數(shù)據(jù)源
在 application.properties 或 application.yml 中配置多個數(shù)據(jù)源,假設我們配置了主數(shù)據(jù)源和從數(shù)據(jù)源。
application.properties 示例:
# 主數(shù)據(jù)源配置 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 # 從數(shù)據(jù)源配置 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
步驟三:自定義動態(tài)數(shù)據(jù)源
Spring Boot 默認的配置是固定的單一數(shù)據(jù)源,但我們可以通過自定義 AbstractRoutingDataSource 來實現(xiàn)動態(tài)數(shù)據(jù)源切換。
1. 自定義 DynamicDataSource 類
AbstractRoutingDataSource 是 Spring 提供的一個用于路由到不同數(shù)據(jù)源的抽象類,我們繼承該類并重寫 determineCurrentLookupKey() 方法,根據(jù)當前線程或請求上下文來決定使用哪個數(shù)據(jù)源。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
2. 定義 DataSourceContextHolder 類
為了實現(xiàn)線程安全地存儲當前數(shù)據(jù)源的上下文,我們使用 ThreadLocal 來保存當前線程的數(shù)據(jù)源標識。
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. 配置動態(tài)數(shù)據(jù)源
在配置類中,將多個數(shù)據(jù)源(如主數(shù)據(jù)庫和從數(shù)據(jù)庫)與 DynamicDataSource 關聯(lián),并將 DynamicDataSource 設置為 Spring 管理的數(shù)據(jù)源。
@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();
}
}
步驟四:切換數(shù)據(jù)源
為了動態(tài)切換數(shù)據(jù)源,我們可以在需要切換數(shù)據(jù)源的地方設置數(shù)據(jù)源類型(如讀寫分離、業(yè)務模塊分庫等)。
1. 在服務層切換數(shù)據(jù)源
在服務方法中,我們可以通過 DataSourceContextHolder.setDataSourceType("primary") 或 DataSourceContextHolder.setDataSourceType("secondary") 來切換數(shù)據(jù)源。
@Service
public class DataService {
// 使用主數(shù)據(jù)源
public void usePrimaryDataSource() {
DataSourceContextHolder.setDataSourceType("primary");
// 執(zhí)行主數(shù)據(jù)庫相關操作
}
// 使用從數(shù)據(jù)源
public void useSecondaryDataSource() {
DataSourceContextHolder.setDataSourceType("secondary");
// 執(zhí)行從數(shù)據(jù)庫相關操作
}
// 清除數(shù)據(jù)源設置
public void clearDataSource() {
DataSourceContextHolder.clearDataSourceType();
}
}
2. 在控制器層切換數(shù)據(jù)源
在控制器層中,可以根據(jù)請求的不同選擇使用不同的數(shù)據(jù)源。
@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統(tǒng)一切換數(shù)據(jù)源
為了更優(yōu)雅地切換數(shù)據(jù)源并解耦,我們可以通過 AOP(面向切面編程)來統(tǒng)一處理數(shù)據(jù)源切換。我們可以創(chuàng)建一個自定義注解來標識哪些方法需要切換數(shù)據(jù)源。
1. 自定義注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceSwitch {
String value() default "primary"; // 默認使用主數(shù)據(jù)源
}
2. 切面類實現(xiàn)
創(chuàng)建切面類,在方法執(zhí)行前根據(jù)注解指定的數(shù)據(jù)源值來切換數(shù)據(jù)源。
@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. 使用注解切換數(shù)據(jù)源
@Service
public class DataService {
@DataSourceSwitch("primary")
public void usePrimaryDataSource() {
// 使用主數(shù)據(jù)源
}
@DataSourceSwitch("secondary")
public void useSecondaryDataSource() {
// 使用從數(shù)據(jù)源
}
}
總結
通過在 Spring Boot 中實現(xiàn)動態(tài)數(shù)據(jù)源切換,我們可以靈活地管理不同數(shù)據(jù)庫的使用,滿足不同業(yè)務場景的需求。無論是簡單的讀寫分離、分庫還是更復雜的業(yè)務需求,都可以通過動態(tài)切換數(shù)據(jù)源來完成。通過結合 AOP 和注解,我們可以更加優(yōu)雅地管理和切換數(shù)據(jù)源,避免了硬編碼和重復代碼的情況,提升了代碼的可維護性和擴展性。
以上就是在SpringBoot項目中動態(tài)切換數(shù)據(jù)源和數(shù)據(jù)庫的詳細步驟的詳細內容,更多關于SpringBoot動態(tài)切換數(shù)據(jù)源和數(shù)據(jù)庫的資料請關注腳本之家其它相關文章!
- SpringBoot實現(xiàn)數(shù)據(jù)源動態(tài)切換的最佳姿勢
- SpringBoot項目中如何動態(tài)切換數(shù)據(jù)源、數(shù)據(jù)庫
- SpringBoot實現(xiàn)動態(tài)數(shù)據(jù)源切換的項目實踐
- SpringBoot實現(xiàn)動態(tài)數(shù)據(jù)源切換的方法總結
- 使用SpringBoot動態(tài)切換數(shù)據(jù)源的實現(xiàn)方式
- Springboot實現(xiàn)多數(shù)據(jù)源切換詳情
- SpringBoot多數(shù)據(jù)源切換實現(xiàn)代碼(Mybaitis)
- SpringBoot實現(xiàn)動態(tài)切換數(shù)據(jù)源的示例代碼
相關文章
springboot3整合knife4j超詳細教程(不帶swagger2玩)
本文詳細介紹了如何在Spring Boot 3項目中整合Knife4j,并提供了配置文件的詳細說明和常用注解的使用方法,感興趣的朋友跟隨小編一起看看吧2025-11-11
Spring Security學習之rememberMe自動登錄的實現(xiàn)
這篇文章主要給大家介紹了關于Spring Security學習之rememberMe自動登錄的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧2020-06-06
spring mvc利用ajax向controller傳遞對象的方法示例
這篇文章主要給大家介紹了關于spring mvc利用ajax向controller傳遞對象的相關資料,文中通過示例代碼將步驟介紹的非常詳細,對大家具有一定的參考學習價值,需要的朋友們下面來跟著小編一起學習學習吧。2017-07-07
Java畢業(yè)設計實戰(zhàn)項目之倉庫管理系統(tǒng)的實現(xiàn)流程
這是一個使用了java+SSM+Maven+Bootstrap+mysql開發(fā)的倉庫管理系統(tǒng),是一個畢業(yè)設計的實戰(zhàn)練習,具有一個倉庫管理系統(tǒng)該有的所有功能,感興趣的朋友快來看看吧2022-01-01
Java為啥能跨平臺(原因解析)JDK/JRE/JVM的關系說明
JVM是Java虛擬機,是Java程序的運行環(huán)境,Java的跨平臺特性是由于JVM的適配性設計,JDK、JRE、JVM三者的關系是JDK> JRE > JVM,本文介紹Java為啥能跨平臺,JDK/JRE/JVM的關系說明,感興趣的朋友一起看看吧2025-12-12
@Async導致controller?404及失效原因解決分析
這篇文章主要為大家介紹了@Async導致controller?404失效問題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07
MyBatis-Plus集成Druid環(huán)境搭建的詳細教程
這篇文章主要介紹了MyBatis-Plus集成Druid環(huán)境搭建的詳細教程,需要的朋友可以參考下2020-08-08

