使用Spring Boot实现动态数据源切换
大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!
在现代应用中,使用多个数据源是一个常见的需求。比如,我们可能需要在读写分离的数据库架构中,根据不同的操作选择不同的数据源。本篇文章将介绍如何使用Spring Boot实现动态数据源切换。
1. 引入必要的依赖
首先,在Spring Boot项目中引入必要的依赖。在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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
2. 配置数据源
在application.yml
文件中配置多个数据源:
spring:
datasource:
primary:
url: jdbc:mysql://localhost:3306/primary_db
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
secondary:
url: jdbc:mysql://localhost:3306/secondary_db
username: root
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
3. 定义数据源配置类
创建一个数据源配置类,用于配置多数据源:
package cn.juwatech.config;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
@Configuration
public class DataSourceConfig {
@Primary
@Bean(name = "primaryDataSource")
@ConfigurationProperties("spring.datasource.primary")
public HikariDataSource primaryDataSource() {
return new HikariDataSource();
}
@Bean(name = "secondaryDataSource")
@ConfigurationProperties("spring.datasource.secondary")
public HikariDataSource secondaryDataSource() {
return new HikariDataSource();
}
}
4. 定义数据源上下文和切换器
创建一个数据源上下文类,用于存储当前线程使用的数据源:
package cn.juwatech.datasource;
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSource(String dataSource) {
contextHolder.set(dataSource);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
}
创建一个数据源切换器,用于动态切换数据源:
package cn.juwatech.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSource();
}
}
5. 配置动态数据源
在配置类中使用动态数据源:
package cn.juwatech.config;
import cn.juwatech.datasource.DynamicRoutingDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class DynamicDataSourceConfig {
@Bean
public DynamicRoutingDataSource dataSource(
@Qualifier("primaryDataSource") DataSource primaryDataSource,
@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>();
dataSourceMap.put("primary", primaryDataSource);
dataSourceMap.put("secondary", secondaryDataSource);
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
dynamicRoutingDataSource.setDefaultTargetDataSource(primaryDataSource);
return dynamicRoutingDataSource;
}
@Bean
public PlatformTransactionManager transactionManager(DynamicRoutingDataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
6. 使用AOP实现动态数据源切换
使用AOP(Aspect-Oriented Programming)实现动态数据源的切换。在需要切换数据源的方法上添加注解,然后在AOP切面中切换数据源。
首先,定义一个注解:
package cn.juwatech.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
String value();
}
然后,创建一个AOP切面类:
package cn.juwatech.aspect;
import cn.juwatech.annotation.DataSource;
import cn.juwatech.datasource.DataSourceContextHolder;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Aspect
@Order(-1)
@Component
public class DataSourceAspect {
@Before("@annotation(dataSource)")
public void changeDataSource(DataSource dataSource) {
DataSourceContextHolder.setDataSource(dataSource.value());
}
}
7. 在服务中使用动态数据源
在需要使用动态数据源的服务方法上添加 @DataSource
注解:
package cn.juwatech.service;
import cn.juwatech.annotation.DataSource;
import cn.juwatech.repository.UserRepository;
import cn.juwatech.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@DataSource("primary")
public List<User> getUsersFromPrimary() {
return userRepository.findAll();
}
@DataSource("secondary")
public List<User> getUsersFromSecondary() {
return userRepository.findAll();
}
}
8. 测试动态数据源切换
编写测试用例,验证动态数据源切换功能:
package cn.juwatech;
import cn.juwatech.service.UserService;
import cn.juwatech.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest
public class DynamicDataSourceTest {
@Autowired
private UserService userService;
@Test
public void testDynamicDataSource() {
List<User> usersFromPrimary = userService.getUsersFromPrimary();
System.out.println("Users from primary data source: " + usersFromPrimary);
List<User> usersFromSecondary = userService.getUsersFromSecondary();
System.out.println("Users from secondary data source: " + usersFromSecondary);
}
}
通过上述步骤,我们成功实现了Spring Boot项目中的动态数据源切换功能。这样,我们可以根据不同的业务需求,在运行时动态选择和切换数据源。
著作权归聚娃科技微赚淘客系统开发者团队,转载请注明出处!