Java 多数据源动态指定数据源实现指南

在开发过程中,尤其是微服务架构应用里,时常会遇到需要连接多个数据库的场景。为了灵活地使用不同的数据源,动态指定数据源就显得尤为重要。本文将带你一步一步实现"Java中多数据源的动态指定"。

流程概述

实现多数据源动态指定数据源的流程可以分为以下几个步骤:

步骤 描述
1 添加相关依赖
2 配置数据源
3 创建数据源切换器
4 使用AOP进行数据源切换
5 测试并验证

1. 添加相关依赖

首先,在你的 pom.xml 中添加以下依赖。假设我们使用Spring Boot框架。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <!-- 其他必要的数据库驱动 -->
</dependencies>
  • spring-boot-starter-data-jpa: 提供JPA和数据库连接功能。
  • HikariCP: 高性能的JDBC连接池。
  • spring-boot-starter-aop: 提供面向切面编程的支持。

2. 配置数据源

接下来,在 application.yml 配置多个数据源。例如:

spring:
  datasource:
    dynamic:
      primary: db1
      datasource:
        db1:
          jdbc-url: jdbc:mysql://localhost:3306/database1
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver
        db2:
          jdbc-url: jdbc:mysql://localhost:3306/database2
          username: root
          password: password
          driver-class-name: com.mysql.cj.jdbc.Driver
  • jdbc-url: 数据库的连接URL。
  • username: 数据库的用户名。
  • password: 数据库的密码。

3. 创建数据源切换器

创建一个 DataSourceContext 类用于存储当前数据源的信息:

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContext.getCurrentDataSource();
    }
}
public class DataSourceContext {
    private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();

    public static void setCurrentDataSource(String dataSource) {
        CONTEXT.set(dataSource);
    }

    public static String getCurrentDataSource() {
        return CONTEXT.get();
    }

    public static void clear() {
        CONTEXT.remove();
    }
}
  • AbstractRoutingDataSource: 允许我们根据给定的条件返回特定的数据源。
  • ThreadLocal: 封装了当前线程的数据源。

4. 使用AOP进行数据源切换

使用AOP拦截方法,以根据注解动态切换数据源。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceAspect {

    @Before("@annotation(dataSource)")
    public void changeDataSource(DataSource dataSource) {
        DataSourceContext.setCurrentDataSource(dataSource.value());
    }
}
  • @Before: 在执行方法之前,用于切换数据源。
  • @annotation(dataSource): 指定方法上的注解。

其中,自定义注解 @DataSource 的代码如下:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface DataSource {
    String value();
}
  • @Target: 指定注解用于方法。
  • @Retention: 指定注解的生命周期。

5. 测试并验证

最后,你可以使用如下示例代码进行测试:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @Autowired
    private UserRepository userRepository; // 假设这是你的JPA接口

    @DataSource("db1")
    @GetMapping("/db1/users")
    public List<User> getUsersFromDb1() {
        return userRepository.findAll(); // 查询数据库1中的用户
    }

    @DataSource("db2")
    @GetMapping("/db2/users")
    public List<User> getUsersFromDb2() {
        return userRepository.findAll(); // 查询数据库2中的用户
    }
}
  • 通过不同的注解,访问不同的数据源。

关系图

用mermaid语法绘制数据源的ER图如下:

erDiagram
    USER {
        int id
        string name
        string email
    }
    DATABASE1 {
        int id
        string name
        string email
    }
    DATABASE2 {
        int id
        string name
        string email
    }
    USER ||--o{ DATABASE1 : belongs_to
    USER ||--o{ DATABASE2 : belongs_to

总结

通过以上步骤,你就能成功实现Java中的多数据源动态指定。通过使用注解加AOP的方式,使得数据源的切换变得灵活与方便。希望本文能帮助你在项目中快速实现多数据源的功能,提升你的开发技能!在开发中如有任何疑问,欢迎随时进行交流。