❃博主首页 : 「码到三十五」 ,同名公众号 :「码到三十五」,wx号 : 「liwu0213」
☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关>
♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基
☠博主专栏 : <mysql高手> <elasticsearch高手> <源码解读> <java核心> <面试攻关>
♝博主的话 : 搬的每块砖,皆为峰峦之基;公众号搜索「码到三十五」关注这个爱发技术干货的coder,一起筑基
在Spring Boot中,通过AbstractRoutingDataSource
实现多数据源连接是一种常见的做法。这种技术允许你在运行时动态地切换数据源,从而支持对多个数据库的操作。Spring Boot中配置和使用AbstractRoutingDataSource
来实现多数据源连接。
1. 添加依赖
pom.xml
文件的依赖,比如Spring Data JPA和数据库驱动:
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- 其他依赖 -->
</dependencies>
2. 配置数据源属性
在application.yml
或application.properties
中配置多个数据源的信息。例如:
spring:datasource:primary:url: jdbc:mysql://localhost:3306/primary_dbusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driversecondary:url: jdbc:mysql://localhost:3306/secondary_dbusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
3. 创建数据源配置类
创建两个数据源配置类,分别用于配置主数据源和次数据源。
@Configuration
public class DataSourceConfig {@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();}
}
4. 创建自定义数据源路由类
扩展AbstractRoutingDataSource
类,并根据上下文信息动态返回数据源。
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSourceType();}
}
5. 创建数据源上下文持有者
用于在运行时设置和获取当前的数据源类型。
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();}
}
6. 配置多数据源
将数据源配置到Spring上下文中,并指定默认的数据源。
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository",entityManagerFactoryRef = "entityManagerFactory",transactionManagerRef = "transactionManager"
)
public class DataSourceRoutingConfig {@Autowired@Qualifier("primaryDataSource")private DataSource primaryDataSource;@Autowired@Qualifier("secondaryDataSource")private DataSource secondaryDataSource;@Beanpublic DataSource dataSource() {DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource();Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("primary", primaryDataSource);targetDataSources.put("secondary", secondaryDataSource);routingDataSource.setTargetDataSources(targetDataSources);routingDataSource.setDefaultTargetDataSource(primaryDataSource);return routingDataSource;}@Beanpublic LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {return builder.dataSource(dataSource()).packages("com.example.entity").persistenceUnit("multiple-pu").build();}@Beanpublic PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {return new JpaTransactionManager(entityManagerFactory);}
}
7. 使用AOP切换数据源
通过AOP在方法执行前设置数据源类型,并在方法执行后清除。
@Aspect
@Component
public class DataSourceAspect {@Before("@annotation(targetDataSource)")public void changeDataSource(JoinPoint point, TargetDataSource targetDataSource) throws Throwable {DataSourceContextHolder.setDataSourceType(targetDataSource.value());}@After("@annotation(targetDataSource)")public void clearDataSource(JoinPoint point, TargetDataSource targetDataSource) {DataSourceContextHolder.clearDataSourceType();}
}
自定义注解TargetDataSource
:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TargetDataSource {String value();
}
8. 使用自定义注解切换数据源
在需要使用特定数据源的方法或类上使用@TargetDataSource
注解。
@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@TargetDataSource("primary")public User findUserById(Long id) {return userRepository.findById(id).orElse(null);}@TargetDataSource("secondary")public User findUserBySecondaryId(Long id) {// 假设secondary数据库有一个类似的表结构return userRepository.findById(id).orElse(null);}
}