SpringBoot實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的完整方案
前言
在 Spring Boot 中實(shí)現(xiàn)多數(shù)據(jù)源連接和切換,可以通過(guò)以下幾種方案來(lái)實(shí)現(xiàn),具體取決于項(xiàng)目的需求、數(shù)據(jù)庫(kù)的使用模式和管理的復(fù)雜性。以下是一個(gè)常見(jiàn)的多數(shù)據(jù)源切換的實(shí)現(xiàn)方案,使用 AbstractRoutingDataSource 來(lái)動(dòng)態(tài)選擇數(shù)據(jù)源。
一、多數(shù)據(jù)源配置與切換方案
在多數(shù)據(jù)源場(chǎng)景中,通常有如下步驟:
- 配置多個(gè)數(shù)據(jù)源的
DataSourcebean。 - 使用
AbstractRoutingDataSource來(lái)動(dòng)態(tài)切換數(shù)據(jù)源。 - 使用
ThreadLocal存儲(chǔ)當(dāng)前的數(shù)據(jù)庫(kù)類(lèi)型或數(shù)據(jù)源標(biāo)識(shí)符。 - 配置數(shù)據(jù)源切換的邏輯,例如基于當(dāng)前的用戶、請(qǐng)求路徑、服務(wù)標(biāo)識(shí)等來(lái)選擇不同的數(shù)據(jù)源。
二、實(shí)現(xiàn)步驟
1. 創(chuàng)建多個(gè)DataSource配置類(lèi)
首先,為每個(gè)數(shù)據(jù)源創(chuàng)建單獨(dú)的配置類(lèi),通常你會(huì)在 application.yml 或 application.properties 中配置每個(gè)數(shù)據(jù)源的連接信息。
spring:
datasource:
# 默認(rèn)數(shù)據(jù)源配置
primary:
url: jdbc:mysql://localhost:3306/primary_db
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
# 第二數(shù)據(jù)源配置
secondary:
url: jdbc:mysql://localhost:3306/secondary_db
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
maximum-pool-size: 10
2. 創(chuàng)建DataSource配置類(lèi)
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {
@Bean(name = "primaryDataSource")
@Primary
@ConfigurationProperties(prefix = "spring.datasource.primary")
public DataSource primaryDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "secondaryDataSource")
@ConfigurationProperties(prefix = "spring.datasource.secondary")
public DataSource secondaryDataSource() {
return DataSourceBuilder.create().build();
}
}
3. 創(chuàng)建動(dòng)態(tài)數(shù)據(jù)源路由類(lèi)
AbstractRoutingDataSource 允許我們?cè)谶\(yùn)行時(shí)根據(jù)某些條件動(dòng)態(tài)選擇數(shù)據(jù)源。
@Configuration
public class DynamicDataSourceConfig {
@Autowired
@Qualifier("primaryDataSource")
private DataSource primaryDataSource;
@Autowired
@Qualifier("secondaryDataSource")
private DataSource secondaryDataSource;
@Bean
public DataSource dataSource() {
// 創(chuàng)建一個(gè)路由數(shù)據(jù)源
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setDefaultTargetDataSource(primaryDataSource); // 默認(rèn)數(shù)據(jù)源
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("primary", primaryDataSource);
targetDataSources.put("secondary", secondaryDataSource);
dataSource.setTargetDataSources(targetDataSources);
return dataSource;
}
}
4. 實(shí)現(xiàn)DynamicDataSource類(lèi)
DynamicDataSource 是繼承自 AbstractRoutingDataSource,它通過(guò) determineCurrentLookupKey() 方法來(lái)動(dòng)態(tài)確定當(dāng)前的數(shù)據(jù)源。
public class DynamicDataSource extends AbstractRoutingDataSource {
// 從 ThreadLocal 獲取當(dāng)前的數(shù)據(jù)庫(kù)標(biāo)識(shí)
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
5. 創(chuàng)建DataSourceContextHolder來(lái)存儲(chǔ)當(dāng)前的數(shù)據(jù)源標(biāo)識(shí)
使用 ThreadLocal 來(lái)保持當(dāng)前線程的數(shù)據(jù)庫(kù)標(biāo)識(shí),以便在不同的數(shù)據(jù)源之間切換。
public class DataSourceContextHolder {
// 使用 ThreadLocal 存儲(chǔ)當(dāng)前線程的數(shù)據(jù)源標(biāo)識(shí)
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();
}
}
6. AOP 方式切換數(shù)據(jù)源
為了在運(yùn)行時(shí)動(dòng)態(tài)切換數(shù)據(jù)源,通常會(huì)使用 AOP 切面來(lái)攔截方法執(zhí)行并指定數(shù)據(jù)源。
@Aspect
@Component
public class DataSourceAspect {
// 通過(guò)注解來(lái)指定使用哪個(gè)數(shù)據(jù)源
@Before("@annotation(dataSource)")
public void switchDataSource(DataSourceType dataSource) {
// 切換數(shù)據(jù)源
DataSourceContextHolder.setDataSourceType(dataSource.value());
}
@After("@annotation(dataSource)")
public void clearDataSource(DataSourceType dataSource) {
// 清理數(shù)據(jù)源標(biāo)識(shí),避免影響其他線程
DataSourceContextHolder.clearDataSourceType();
}
}
7. 自定義注解來(lái)指定數(shù)據(jù)源
創(chuàng)建一個(gè)自定義注解 DataSourceType,用于指定當(dāng)前方法執(zhí)行時(shí)需要使用的數(shù)據(jù)源。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceType {
String value() default "primary"; // 數(shù)據(jù)源標(biāo)識(shí),默認(rèn)使用primary數(shù)據(jù)源
}
8. 在 Service 層使用注解指定數(shù)據(jù)源
在 Service 層,可以使用剛才創(chuàng)建的 @DataSourceType 注解來(lái)指定不同的方法使用不同的數(shù)據(jù)源。
@Service
public class UserService {
@DataSourceType("primary")
public List<User> getPrimaryUsers() {
// 查詢主數(shù)據(jù)庫(kù)
return userRepository.findAll();
}
@DataSourceType("secondary")
public List<User> getSecondaryUsers() {
// 查詢次數(shù)據(jù)庫(kù)
return secondaryUserRepository.findAll();
}
}
總結(jié)
- 數(shù)據(jù)源配置:為每個(gè)數(shù)據(jù)源配置
DataSourceBean。 - 動(dòng)態(tài)數(shù)據(jù)源路由:使用
AbstractRoutingDataSource來(lái)實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源。 - ThreadLocal存儲(chǔ):使用
ThreadLocal存儲(chǔ)和獲取當(dāng)前線程的數(shù)據(jù)源標(biāo)識(shí)。 - AOP切換數(shù)據(jù)源:使用 AOP 來(lái)攔截方法并切換數(shù)據(jù)源。
- 注解方式指定數(shù)據(jù)源:通過(guò)自定義注解來(lái)指定方法使用的具體數(shù)據(jù)源。
這種方式比較靈活,能夠在運(yùn)行時(shí)根據(jù)業(yè)務(wù)需求選擇不同的數(shù)據(jù)源,適用于多數(shù)據(jù)源的場(chǎng)景,尤其是分庫(kù)分表、讀寫(xiě)分離等復(fù)雜應(yīng)用場(chǎng)景。
到此這篇關(guān)于SpringBoot實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的完整方案的文章就介紹到這了,更多相關(guān)SpringBoot多數(shù)據(jù)源連接和切換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
eclipse創(chuàng)建多層包(多級(jí)包)全過(guò)程
這篇文章主要介紹了eclipse創(chuàng)建多層包(多級(jí)包)全過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
基于surging跨網(wǎng)關(guān)跨語(yǔ)言進(jìn)行緩存降級(jí)的問(wèn)題小結(jié)
surging是一款開(kāi)源的微服務(wù)引擎,包含了rpc服務(wù)治理,中間件,以及多種外部協(xié)議來(lái)解決各個(gè)行業(yè)的業(yè)務(wù)問(wèn)題,這篇文章主要介紹了如何基于surging跨網(wǎng)關(guān)跨語(yǔ)言進(jìn)行緩存降級(jí),需要的朋友可以參考下2024-05-05
Java窗體中關(guān)于默認(rèn)布局管理器容易踩的坑及解決
這篇文章主要介紹了Java窗體中關(guān)于默認(rèn)布局管理器容易踩的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
Java BigDecimal類(lèi)的使用和注意事項(xiàng)
這篇文章主要講解Java中BigDecimal類(lèi)的用法,并簡(jiǎn)單介紹一些注意事項(xiàng),希望能給大家做一個(gè)參考。2016-06-06
Spring中Bean有關(guān)NullPointerException異常的原因分析
在Spring中使用@Autowired注解注入的bean不能在靜態(tài)上下文中訪問(wèn),否則會(huì)導(dǎo)致NullPointerException,解決方法包括避免在靜態(tài)方法中使用注入的bean,或者使用Spring的ApplicationContext來(lái)獲取bean,但后者不推薦2024-12-12

