SpringBoot中Druid連接池與多數(shù)據(jù)源切換的方法
多數(shù)據(jù)源切換原理
多數(shù)據(jù)源切換的原理主要基于 Spring 的 AbstractRoutingDataSource 類。AbstractRoutingDataSource 類允許根據(jù)運行時上下文動態(tài)選擇數(shù)據(jù)源。其核心在于實現(xiàn) determineCurrentLookupKey 方法,該方法決定當前操作使用哪個數(shù)據(jù)源。 AbstractRoutingDataSource 實現(xiàn)多數(shù)據(jù)源切換的原理:
1. 數(shù)據(jù)源映射
AbstractRoutingDataSource內(nèi)部維護了一個映射(Map),用于存儲數(shù)據(jù)源標識(key)和對應的數(shù)據(jù)源實例(value)。這個映射允許根據(jù)數(shù)據(jù)源標識快速查找和獲取對應的數(shù)據(jù)源。
2. 數(shù)據(jù)源標識的確定
AbstractRoutingDataSource提供了一個抽象方法determineCurrentLookupKey(),該方法用于確定當前需要使用的數(shù)據(jù)源標識。這個方法需要由子類實現(xiàn),以返回當前線程或請求應該使用的數(shù)據(jù)源標識。
3. 數(shù)據(jù)源的選擇與連接獲取
- 當應用程序需要獲取數(shù)據(jù)庫連接時,
AbstractRoutingDataSource的getConnection()方法會被調(diào)用。這個方法首先調(diào)用determineCurrentLookupKey()方法來獲取當前的數(shù)據(jù)源標識,然后根據(jù)這個標識從內(nèi)部映射中查找對應的數(shù)據(jù)源。 - 一旦找到了對應的數(shù)據(jù)源,
AbstractRoutingDataSource就會調(diào)用該數(shù)據(jù)源的getConnection()方法來獲取實際的數(shù)據(jù)庫連接,并將這個連接返回給應用程序。
4. 數(shù)據(jù)源切換的實現(xiàn)
- 為了實現(xiàn)數(shù)據(jù)源的動態(tài)切換,通常會在子類中重寫
determineCurrentLookupKey()方法,并根據(jù)當前的上下文(如線程變量)來確定返回的數(shù)據(jù)源標識。 - 此外,通常會使用
ThreadLocal來存儲每個線程的數(shù)據(jù)源標識,這樣每個線程都可以獨立地切換數(shù)據(jù)源而不會互相干擾。
實現(xiàn)步驟
1. 依賴
引入 MySQL 和 Druid 的依賴
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
2. 配置數(shù)據(jù)源
在 application.yml 文件中配置多個數(shù)據(jù)源。
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
druid:
datasource1:
url: jdbc:mysql://localhost:3306/master_db
username: root
password: password
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
datasource2:
url: jdbc:mysql://localhost:3306/slave_db
username: root
password: password
initial-size: 5
min-idle: 5
max-active: 20
max-wait: 60000
3. 創(chuàng)建數(shù)據(jù)源配置類
創(chuàng)建一個配置類來定義數(shù)據(jù)源 Bean。
@Configuration
public class DataSourceConfig {
@Bean
@ConditionalOnProperty(prefix = "spring.datasource.druid", name = "datasource1")
@ConfigurationProperties(prefix = "spring.datasource.druid.datasource1")
public DataSource dataSource1() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConditionalOnProperty(prefix = "spring.datasource.druid", name = "datasource2")
@ConfigurationProperties(prefix = "spring.datasource.druid.datasource2")
public DataSource dataSource2() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@Primary
public DataSource dynamicDataSource() {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(dataSource1());
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("dataSource1", dataSource1());
targetDataSources.put("dataSource2", dataSource2());
dynamicDataSource.setTargetDataSources(targetDataSources);
return dynamicDataSource;
}
}
4. 實現(xiàn) AbstractRoutingDataSource
創(chuàng)建一個繼承自 AbstractRoutingDataSource 的類,并實現(xiàn) determineCurrentLookupKey 方法。
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
5. 創(chuàng)建 DataSourceContextHolder
創(chuàng)建一個工具類來保存當前線程的數(shù)據(jù)源信息。
public class DataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
public static void setDataSource(String dataSource) {
CONTEXT_HOLDER.set(dataSource);
}
public static String getDataSource() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSource() {
CONTEXT_HOLDER.remove();
}
}
6. AOP動態(tài)切換數(shù)據(jù)源
使用 AOP 在方法執(zhí)行前后切換數(shù)據(jù)源。
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class DataSourceAspect {
// 方法或者類上的橫切點
@Pointcut("@annotation(dataSource) || @within(dataSource)")
public void dataSourcePointcut(DataSource dataSource) {}
@Before("dataSourcePointcut(dataSource)")
public void switchDataSource(JoinPoint joinPoint, DataSource dataSource) {
// 從注解中獲取數(shù)據(jù)源標識
String dataSourceKey = dataSource.value();
// 切換到指定的數(shù)據(jù)源
DataSourceContextHolder.setDataSourceType(dataSourceKey);
}
@AfterReturning(pointcut = "dataSourcePointcut(dataSource)", returning = "result")
public void restoreDataSource(JoinPoint joinPoint, DataSource dataSource, Object result) {
// 恢復默認數(shù)據(jù)源(可選)
DataSourceContextHolder.clearDataSourceType();
}
}
/**
* 自定義注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value() default "dataSource1";
}
7. 使用自定義注解
在需要切換數(shù)據(jù)源的方法上使用自定義注解。
注意
- 數(shù)據(jù)源切換的邏輯應該盡可能簡單和高效,以避免對應用程序性能產(chǎn)生負面影響。
- 在切換數(shù)據(jù)源時,需要注意事務管理的問題,確保在同一個事務中只使用同一個數(shù)據(jù)源。
到此這篇關于SpringBoot中Druid連接池與多數(shù)據(jù)源切換的方法的文章就介紹到這了,更多相關SpringBoot Druid與數(shù)據(jù)源切換內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- SpringBoot整合mybatis使用Druid做連接池的方式
- Springboot中加入druid連接池
- springboot2.0配置連接池(hikari、druid)的方法
- SpringBoot整合Druid實現(xiàn)數(shù)據(jù)庫連接池和監(jiān)控
- springboot項目整合druid數(shù)據(jù)庫連接池的實現(xiàn)
- springboot集成druid連接池配置的方法
- springboot整合druid連接池的步驟
- SpringBoot使用 druid 連接池來優(yōu)化分頁語句
- SpringBoot整合Druid數(shù)據(jù)庫連接池的方法
- 解決Spring Boot中Druid連接池“discard long time none received connection“警告
相關文章
Spring?invokeBeanFactoryPostProcessors方法刨析源碼
invokeBeanFactoryPostProcessors該方法會實例化所有BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor的實例并且執(zhí)行postProcessBeanFactory與postProcessBeanDefinitionRegistry方法2023-01-01
詳解Spring Cloud Gateway 數(shù)據(jù)庫存儲路由信息的擴展方案
這篇文章主要介紹了詳解Spring Cloud Gateway 數(shù)據(jù)庫存儲路由信息的擴展方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11
Java設計模式之中介者模式(Mediator Pattern)簡介
這篇文章主要介紹了Java設計模式之中介者模式(Mediator Pattern),需要的朋友可以參考下2014-07-07
Spring boot2X負載均衡和反向代理實現(xiàn)過程解析
這篇文章主要介紹了Spring boot2X負載均衡和反向代理實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-12-12
mybatis報錯元素內(nèi)容必須由格式正確的字符數(shù)據(jù)或標記組成異常的解決辦法
今天小編就為大家分享一篇關于mybatis查詢出錯解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12

