在Spring Boot项目中如何动态切换数据源、数据库?
全文目录:
- 开篇语
- 前言
- 动态切换数据源的需求
- 步骤一:引入相关依赖
- 步骤二:配置多个数据源
- 示例:主库(Primary DataSource)配置
- `application.properties` 配置文件
- 步骤三:自定义动态数据源
- 1. 自定义`AbstractRoutingDataSource`类
- 2. 定义`DataSourceContextHolder`类
- 3. 配置`DynamicDataSource`为数据源
- 步骤四:使用动态数据源
- 示例:在业务方法中切换数据源
- 在控制器中切换数据源
- 步骤五:使用AOP统一切换数据源
- 1. 自定义注解
- 2. 切面实现
- 3. 使用注解切换数据源
- 总结
- 文末
开篇语
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。
我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在一些复杂的企业级应用中,可能会有多个数据库的使用需求,比如读写分离、数据库分库、不同业务模块使用不同数据库等。Spring Boot作为一种快速开发框架,提供了强大的配置和扩展能力,可以实现动态切换数据源和数据库。
本文将介绍在Spring Boot项目中,如何实现动态切换数据源和数据库,包括切换的原理、步骤和实现方式。我们将使用Spring的AbstractRoutingDataSource
实现多数据源动态切换。
动态切换数据源的需求
在实际开发中,我们可能会遇到以下几种需求:
- 读写分离:将写操作和读操作分别使用不同的数据库,以提高数据库的性能。
- 多数据库支持:项目需要支持多个数据库,比如主库和备库、不同业务模块使用不同的数据库。
- 按条件切换数据源:根据特定的条件(如用户、请求来源等)选择不同的数据源。
为了满足这些需求,我们可以利用Spring提供的动态数据源功能,通过自定义一个AbstractRoutingDataSource
,在每次操作时动态地选择不同的数据源。
步骤一:引入相关依赖
首先,确保你的Spring Boot项目中已经包含了JPA、DataSource等相关依赖。如果使用的是Spring Boot 2.x及以上版本,通常会自动引入这些依赖,但仍需确认在pom.xml
中有如下依赖:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency><groupId>com.zaxxer</groupId><artifactId>HikariCP</artifactId> <!-- 连接池 -->
</dependency>
步骤二:配置多个数据源
首先,定义两个或更多的数据源配置类,并配置数据源的基本信息。比如,我们配置主库(primaryDataSource
)和从库(secondaryDataSource
)。
示例:主库(Primary DataSource)配置
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class DataSourceConfig {@Primary@Bean(name = "primaryDataSource")@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();}}
application.properties
配置文件
在application.properties
文件中,配置主库和从库的数据库连接信息:
# 主数据库配置
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# 从数据库配置
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
步骤三:自定义动态数据源
1. 自定义AbstractRoutingDataSource
类
AbstractRoutingDataSource
是Spring提供的一个用于动态切换数据源的抽象类。我们需要继承该类并重写determineCurrentLookupKey()
方法,该方法用于决定当前请求使用哪个数据源。
public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {// 根据当前的上下文选择数据源return DataSourceContextHolder.getDataSourceType();}
}
2. 定义DataSourceContextHolder
类
DataSourceContextHolder
类用于保存当前线程的数据源信息。它通过ThreadLocal
来存储数据源,以确保线程安全。
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. 配置DynamicDataSource
为数据源
在数据源配置中,将DynamicDataSource
配置为数据源,确保它能够根据DataSourceContextHolder
中存储的数据源类型动态切换。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class DataSourceConfig {@Primary@Beanpublic 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;}
}
步骤四:使用动态数据源
在使用动态数据源时,通常是在特定的业务逻辑中切换数据源。例如,您可以在服务层或控制器层根据不同的业务需求来切换数据源。
示例:在业务方法中切换数据源
@Service
public class DataService {public void usePrimaryDataSource() {// 切换到主数据库DataSourceContextHolder.setDataSourceType("primary");// 执行主数据库相关操作}public void useSecondaryDataSource() {// 切换到从数据库DataSourceContextHolder.setDataSourceType("secondary");// 执行从数据库相关操作}public void clearDataSource() {// 清除数据源设置,恢复默认DataSourceContextHolder.clearDataSourceType();}
}
在控制器中切换数据源
@RestController
@RequestMapping("/data")
public class DataController {@Autowiredprivate DataService dataService;@GetMapping("/usePrimary")public String usePrimaryDataSource() {dataService.usePrimaryDataSource();return "Used Primary DataSource";}@GetMapping("/useSecondary")public String useSecondaryDataSource() {dataService.useSecondaryDataSource();return "Used Secondary DataSource";}
}
步骤五:使用AOP统一切换数据源
为了更好地解耦数据源切换逻辑,可以使用AOP(面向切面编程)来统一处理数据源切换。我们可以定义一个AOP切面,在方法执行前根据注解或其他条件自动切换数据源。
1. 自定义注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSourceSwitch {String value() default "primary"; // 默认使用主数据库
}
2. 切面实现
@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. 使用注解切换数据源
@Service
public class DataService {@DataSourceSwitch("primary")public void usePrimaryDataSource() {// 使用主数据库}@DataSourceSwitch("secondary")public void useSecondaryDataSource() {// 使用从数据库}
}
总结
在Spring Boot项目中动态切换数据源是一个常见需求,特别是当涉及到读写分离、分库等复杂场景时。通过继承AbstractRoutingDataSource
并结合ThreadLocal
来保存当前数据源信息,我们可以实现灵活的数据源切换。此外,通过AOP和自定义注解,我们可以更加优雅和解耦地实现数据源的动态切换。在多数据源的项目中,掌握这种动态切换的实现方法,对于提升项目的可扩展性和可维护性具有重要意义。
… …
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
… …
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
版权声明:本文由作者原创,转载请注明出处,谢谢支持!