java动态数据源
时间: 2025-05-27 22:25:35 浏览: 13
### Java 动态数据源实现方式
#### 1. 使用 `AbstractRoutingDataSource` 实现动态数据源
`AbstractRoutingDataSource` 是 Spring 提供的一个抽象类,用于支持动态数据源切换。其实现逻辑基于键值映射的方式,在运行时决定使用哪个实际的数据源。
以下是其基本实现流程:
- 定义一个继承自 `AbstractRoutingDataSource` 的类,并重写 `determineCurrentLookupKey()` 方法来返回当前线程绑定的数据源标识符。
- 配置多个数据源并注册到 `AbstractRoutingDataSource` 中。
- 使用 ThreadLocal 来保存当前线程所需使用的数据源名称。
代码示例如下:
```java
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSource(String dataSourceName) {
contextHolder.set(dataSourceName);
}
public static String getDataSource() {
return contextHolder.get();
}
public static void clearDataSource() {
contextHolder.remove();
}
@Override
protected Object determineCurrentLookupKey() {
return contextHolder.get(); // 返回当前线程绑定的数据源名称
}
}
```
此部分实现了动态数据源的核心功能[^1]。
---
#### 2. 数据源配置与初始化
在 Spring Boot 应用程序中,可以通过配置文件定义多个数据源,并将其注入到 `DynamicDataSource` 类中。
以下是一个简单的配置示例:
```yaml
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/master_db?useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave_db?useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
```
对应的 Java 配置代码如下:
```java
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource);
targetDataSources.put("slave", slaveDataSource);
DynamicDataSource dynamicDataSource = new DynamicDataSource();
dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 设置默认数据源为主库
dynamicDataSource.setTargetDataSources(targetDataSources); // 注册目标数据源
return dynamicDataSource;
}
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
}
```
以上代码展示了如何将主从数据库配置为动态数据源的一部分。
---
#### 3. AOP 拦截器实现数据源切换
为了简化开发过程,通常会结合 AOP 技术自动完成数据源的切换操作。通过自定义注解标记需要切换数据源的方法或类,AOP 切面会在执行前设置对应的数据源。
##### 自定义注解
```java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
String value() default ""; // 默认为空字符串
}
```
##### AOP 切面实现
```java
@Aspect
@Component
public class DataSourceAspect {
@Around("@annotation(DataSource)")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
if (method.isAnnotationPresent(DataSource.class)) {
DataSource ds = method.getAnnotation(DataSource.class);
String dataSourceName = ds.value();
DynamicDataSource.setDataSource(dataSourceName); // 设置数据源
}
try {
return point.proceed();
} finally {
DynamicDataSource.clearDataSource(); // 清除数据源上下文
}
}
}
```
该切面会在方法调用前后分别设置和清除数据源,从而确保线程安全[^3]。
---
#### 4. MyBatis Plus 插件实现多数据源管理
除了手动实现外,还可以借助第三方工具如 MyBatis Plus 提供的插件机制快速搭建多数据源环境。MyBatis Plus 支持通过拦截 SQL 执行请求的方式来动态指定数据源。
核心思路是在每次查询之前判断所需的表属于哪个数据源,并据此调整底层 JDBC 连接对象。
代码片段如下:
```java
// 创建一个多租户处理器
@Bean
public IDynamicDataSourceProcessor mybatisPlusDynamicDataSourceProcessor() {
return new IDynamicDataSourceProcessor() {
@Override
public String processDatasource(EntityWrapper<?> entityWrapper) {
// 根据实体类或其他条件动态获取数据源名
return "dataSourceName";
}
};
}
```
更多细节可参考官方文档说明[^2]。
---
#### 总结
综上所述,Java 动态数据源主要依赖于 `AbstractRoutingDataSource` 和 ThreadLocal 结合的技术方案;同时也可以引入成熟的开源框架(如 MyBatis Plus 或 Dynamic Datasource Starter)进一步降低开发成本。每种方式各有优劣,需根据项目需求灵活选用。
---
阅读全文
相关推荐















