文章目录
前言
在 Spring Boot 中实现多数据源连接和切换,可以通过以下几种方案来实现,具体取决于项目的需求、数据库的使用模式和管理的复杂性。以下是一个常见的多数据源切换的实现方案,使用 AbstractRoutingDataSource 来动态选择数据源。
一、多数据源配置与切换方案
在多数据源场景中,通常有如下步骤:
- 配置多个数据源的
DataSource
bean。 - 使用
AbstractRoutingDataSource
来动态切换数据源。 - 使用
ThreadLocal
存储当前的数据库类型或数据源标识符。 - 配置数据源切换的逻辑,例如基于当前的用户、请求路径、服务标识等来选择不同的数据源。
二、实现步骤
1. 创建多个
DataSource
配置类
首先,为每个数据源创建单独的配置类,通常你会在
application.yml
或
application.properties
中配置每个数据源的连接信息。
spring:datasource:# 默认数据源配置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# 第二数据源配置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. 创建
DataSource
配置类
@Configuration@EnableTransactionManagementpublicclassDataSourceConfig{@Bean(name ="primaryDataSource")@Primary@ConfigurationProperties(prefix ="spring.datasource.primary")publicDataSourceprimaryDataSource(){returnDataSourceBuilder.create().build();}@Bean(name ="secondaryDataSource")@ConfigurationProperties(prefix ="spring.datasource.secondary")publicDataSourcesecondaryDataSource(){returnDataSourceBuilder.create().build();}}
3. 创建动态数据源路由类
AbstractRoutingDataSource
允许我们在运行时根据某些条件动态选择数据源。
@ConfigurationpublicclassDynamicDataSourceConfig{@Autowired@Qualifier("primaryDataSource")privateDataSource primaryDataSource;@Autowired@Qualifier("secondaryDataSource")privateDataSource secondaryDataSource;@BeanpublicDataSourcedataSource(){// 创建一个路由数据源DynamicDataSource dataSource =newDynamicDataSource();
dataSource.setDefaultTargetDataSource(primaryDataSource);// 默认数据源Map<Object,Object> targetDataSources =newHashMap<>();
targetDataSources.put("primary", primaryDataSource);
targetDataSources.put("secondary", secondaryDataSource);
dataSource.setTargetDataSources(targetDataSources);return dataSource;}}
4. 实现
DynamicDataSource
类
DynamicDataSource
是继承自
AbstractRoutingDataSource
,它通过
determineCurrentLookupKey()
方法来动态确定当前的数据源。
publicclassDynamicDataSourceextendsAbstractRoutingDataSource{// 从 ThreadLocal 获取当前的数据库标识@OverrideprotectedObjectdetermineCurrentLookupKey(){returnDataSourceContextHolder.getDataSourceType();}}
5. 创建
DataSourceContextHolder
来存储当前的数据源标识
使用
ThreadLocal
来保持当前线程的数据库标识,以便在不同的数据源之间切换。
publicclassDataSourceContextHolder{// 使用 ThreadLocal 存储当前线程的数据源标识privatestaticfinalThreadLocal<String> contextHolder =newThreadLocal<>();publicstaticvoidsetDataSourceType(String dataSourceType){
contextHolder.set(dataSourceType);}publicstaticStringgetDataSourceType(){return contextHolder.get();}publicstaticvoidclearDataSourceType(){
contextHolder.remove();}}
6. AOP 方式切换数据源
为了在运行时动态切换数据源,通常会使用 AOP 切面来拦截方法执行并指定数据源。
@Aspect@ComponentpublicclassDataSourceAspect{// 通过注解来指定使用哪个数据源@Before("@annotation(dataSource)")publicvoidswitchDataSource(DataSourceType dataSource){// 切换数据源DataSourceContextHolder.setDataSourceType(dataSource.value());}@After("@annotation(dataSource)")publicvoidclearDataSource(DataSourceType dataSource){// 清理数据源标识,避免影响其他线程DataSourceContextHolder.clearDataSourceType();}}
7. 自定义注解来指定数据源
创建一个自定义注解
DataSourceType
,用于指定当前方法执行时需要使用的数据源。
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceDataSourceType{Stringvalue()default"primary";// 数据源标识,默认使用primary数据源}
8. 在 Service 层使用注解指定数据源
在 Service 层,可以使用刚才创建的
@DataSourceType
注解来指定不同的方法使用不同的数据源。
@ServicepublicclassUserService{@DataSourceType("primary")publicList<User>getPrimaryUsers(){// 查询主数据库return userRepository.findAll();}@DataSourceType("secondary")publicList<User>getSecondaryUsers(){// 查询次数据库return secondaryUserRepository.findAll();}}
总结
- 数据源配置:为每个数据源配置
DataSource
Bean。 - 动态数据源路由:使用
AbstractRoutingDataSource
来实现动态切换数据源。 - ThreadLocal存储:使用
ThreadLocal
存储和获取当前线程的数据源标识。 - AOP切换数据源:使用 AOP 来拦截方法并切换数据源。
- 注解方式指定数据源:通过自定义注解来指定方法使用的具体数据源。
这种方式比较灵活,能够在运行时根据业务需求选择不同的数据源,适用于多数据源的场景,尤其是分库分表、读写分离等复杂应用场景。
版权归原作者 小呆呆^ 所有, 如有侵权,请联系我们删除。