Spring?Boot實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的解決方案
前言
在 Spring Boot 中實(shí)現(xiàn)多數(shù)據(jù)源連接和切換,可以通過以下幾種方案來實(shí)現(xiàn),具體取決于項(xiàng)目的需求、數(shù)據(jù)庫的使用模式和管理的復(fù)雜性。以下是一個(gè)常見的多數(shù)據(jù)源切換的實(shí)現(xiàn)方案,使用 AbstractRoutingDataSource 來動(dòng)態(tài)選擇數(shù)據(jù)源。
一、多數(shù)據(jù)源配置與切換方案
在多數(shù)據(jù)源場景中,通常有如下步驟:
- 配置多個(gè)數(shù)據(jù)源的
DataSource
bean。 - 使用
AbstractRoutingDataSource
來動(dòng)態(tài)切換數(shù)據(jù)源。 - 使用
ThreadLocal
存儲(chǔ)當(dāng)前的數(shù)據(jù)庫類型或數(shù)據(jù)源標(biāo)識(shí)符。 - 配置數(shù)據(jù)源切換的邏輯,例如基于當(dāng)前的用戶、請求路徑、服務(wù)標(biāo)識(shí)等來選擇不同的數(shù)據(jù)源。
二、實(shí)現(xiàn)步驟
1. 創(chuàng)建多個(gè) DataSource
配置類
首先,為每個(gè)數(shù)據(jù)源創(chuàng)建單獨(dú)的配置類,通常你會(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
配置類
@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ù)源路由類
AbstractRoutingDataSource
允許我們在運(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
類
DynamicDataSource
是繼承自 AbstractRoutingDataSource
,它通過 determineCurrentLookupKey()
方法來動(dòng)態(tài)確定當(dāng)前的數(shù)據(jù)源。
public class DynamicDataSource extends AbstractRoutingDataSource { // 從 ThreadLocal 獲取當(dāng)前的數(shù)據(jù)庫標(biāo)識(shí) @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSourceType(); } }
5. 創(chuàng)建 DataSourceContextHolder
來存儲(chǔ)當(dāng)前的數(shù)據(jù)源標(biāo)識(shí)
使用 ThreadLocal
來保持當(dāng)前線程的數(shù)據(jù)庫標(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 切面來攔截方法執(zhí)行并指定數(shù)據(jù)源。
@Aspect @Component public class DataSourceAspect { // 通過注解來指定使用哪個(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. 自定義注解來指定數(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
注解來指定不同的方法使用不同的數(shù)據(jù)源。
@Service public class UserService { @DataSourceType("primary") public List<User> getPrimaryUsers() { // 查詢主數(shù)據(jù)庫 return userRepository.findAll(); } @DataSourceType("secondary") public List<User> getSecondaryUsers() { // 查詢次數(shù)據(jù)庫 return secondaryUserRepository.findAll(); } }
總結(jié)
- 數(shù)據(jù)源配置:為每個(gè)數(shù)據(jù)源配置
DataSource
Bean。 - 動(dòng)態(tài)數(shù)據(jù)源路由:使用
AbstractRoutingDataSource
來實(shí)現(xiàn)動(dòng)態(tài)切換數(shù)據(jù)源。 - ThreadLocal存儲(chǔ):使用
ThreadLocal
存儲(chǔ)和獲取當(dāng)前線程的數(shù)據(jù)源標(biāo)識(shí)。 - AOP切換數(shù)據(jù)源:使用 AOP 來攔截方法并切換數(shù)據(jù)源。
- 注解方式指定數(shù)據(jù)源:通過自定義注解來指定方法使用的具體數(shù)據(jù)源。
這種方式比較靈活,能夠在運(yùn)行時(shí)根據(jù)業(yè)務(wù)需求選擇不同的數(shù)據(jù)源,適用于多數(shù)據(jù)源的場景,尤其是分庫分表、讀寫分離等復(fù)雜應(yīng)用場景。
到此這篇關(guān)于Spring Boot實(shí)現(xiàn)多數(shù)據(jù)源連接和切換的文章就介紹到這了,更多相關(guān)Spring Boot多數(shù)據(jù)源連接和切換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)字符串轉(zhuǎn)為駝峰格式的方法詳解
這篇文章主要介紹了如何利用Java語言實(shí)現(xiàn)字符串轉(zhuǎn)為駝峰格式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-07-07IntelliJ IDEA 2023.2正式發(fā)布新UI和Profiler轉(zhuǎn)正(最新推薦)
北京時(shí)間2023年7月26日,IntelliJ IDEA 2023.2正式發(fā)布,IntelliJ IDEA 2023.2 引入 AI Assistant(AI助手),通過一組由 AI 提供支持的功能助力開發(fā),今天給大家分享IntelliJ IDEA 2023.2正式發(fā)布新UI和Profiler轉(zhuǎn)正,感興趣的朋友一起看看吧2023-10-10Java人民幣小寫轉(zhuǎn)大寫字符串的實(shí)現(xiàn)
這篇文章主要介紹了Java人民幣小寫轉(zhuǎn)大寫字符串的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04Java實(shí)現(xiàn)文件上傳服務(wù)器和客戶端
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)文件上傳服務(wù)器和客戶端,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01