当前位置: 首页 > article >正文

Spring Boot 动态数据源实操指南

在实际开发中,我们经常会遇到需要动态切换数据源的场景,比如多租户系统、读写分离、分库分表等。Spring Boot 提供了灵活的配置方式,结合 AbstractRoutingDataSource 可以轻松实现动态数据源切换。本文将带你一步步实现 Spring Boot 动态数据源的配置与使用。


一、动态数据源的原理

Spring Boot 的动态数据源核心原理是通过 AbstractRoutingDataSource 实现数据源的路由。AbstractRoutingDataSource 是一个抽象类,它允许我们根据当前的上下文(如线程局部变量)动态选择目标数据源。

核心流程:

  1. 定义多个数据源(如主库、从库)。
  2. 继承 AbstractRoutingDataSource,实现 determineCurrentLookupKey() 方法,返回当前线程需要使用的数据源标识。
  3. 通过 AOP 或手动切换的方式,动态设置数据源标识。

二、实现步骤

1. 创建 Spring Boot 项目

使用 Spring Initializr 创建一个 Spring Boot 项目,添加以下依赖:

  • Spring Web
  • Spring Data JPA
  • MySQL Driver
  • HikariCP(连接池)
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
    </dependency>
</dependencies>

2. 配置多数据源

application.yml 中配置多个数据源,例如主库和从库:

spring:
  datasource:
    master:
      jdbc-url: jdbc:mysql://localhost:3306/master_db
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver
    slave:
      jdbc-url: jdbc:mysql://localhost:3306/slave_db
      username: root
      password: root
      driver-class-name: com.mysql.cj.jdbc.Driver

3. 创建数据源配置类

通过 Java 配置类加载多个数据源。

@Configuration
public class DataSourceConfig {

    @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();
    }
}

4. 实现动态数据源路由

创建 DynamicDataSource 类继承 AbstractRoutingDataSource,并实现 determineCurrentLookupKey() 方法。

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceKey();
    }
}

5. 创建数据源上下文管理类

使用 ThreadLocal 保存当前线程的数据源标识。

public class DataSourceContextHolder {

    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setDataSourceKey(String key) {
        contextHolder.set(key);
    }

    public static String getDataSourceKey() {
        return contextHolder.get();
    }

    public static void clearDataSourceKey() {
        contextHolder.remove();
    }
}

6. 配置动态数据源

将多个数据源注入到 DynamicDataSource 中。

@Configuration
public class DynamicDataSourceConfig {

    @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;
    }
}

7. 配置事务管理器

由于动态数据源的切换会影响事务管理,需要配置一个支持动态数据源的事务管理器。

@Bean
public PlatformTransactionManager transactionManager(DataSource dynamicDataSource) {
    return new DataSourceTransactionManager(dynamicDataSource);
}

8. 使用 AOP 动态切换数据源

通过 AOP 在方法执行前切换数据源。

@Aspect
@Component
public class DataSourceAspect {

    @Before("@annotation(com.example.demo.annotation.Master)")
    public void setMasterDataSource() {
        DataSourceContextHolder.setDataSourceKey("master");
    }

    @Before("@annotation(com.example.demo.annotation.Slave)")
    public void setSlaveDataSource() {
        DataSourceContextHolder.setDataSourceKey("slave");
    }

    @After("@annotation(com.example.demo.annotation.Master) || @annotation(com.example.demo.annotation.Slave)")
    public void clearDataSource() {
        DataSourceContextHolder.clearDataSourceKey();
    }
}

9. 定义注解

为了方便切换数据源,定义两个注解:@Master@Slave

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Master {
}

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Slave {
}

10. 测试动态数据源

在 Service 层使用注解切换数据源。

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Master
    public void addUser(User user) {
        userRepository.save(user);
    }

    @Slave
    public List<User> getUsers() {
        return userRepository.findAll();
    }
}

三、总结

通过以上步骤,我们实现了一个简单的 Spring Boot 动态数据源切换功能。核心点包括:

  1. 使用 AbstractRoutingDataSource 实现数据源路由。
  2. 通过 ThreadLocal 管理当前线程的数据源标识。
  3. 使用 AOP 和注解简化数据源切换。

动态数据源切换是一个非常实用的功能,适用于多租户、读写分离等场景。希望本文能帮助你更好地理解和应用 Spring Boot 动态数据源技术!


http://www.kler.cn/a/548483.html

相关文章:

  • 新电脑配置安装下载
  • FreeBSD系统使用pyenv安装不同版本python,比如python3.12
  • 景联文科技:以精准标注赋能AI未来,打造高质量数据基石
  • 数据库报错1045-Access denied for user ‘root‘@‘localhost‘ (using password: YES)解决方式
  • Java 单例模式 (Singleton)
  • MySQL 插入替换语句(replace into statement)
  • C语言中的对象、左值、右值、序列点、副作用的概念
  • Django 创建表时 “__str__ ”方法的使用
  • DeepSeek生成思维导图
  • K8S容器启动提示:0/2 nodes are available: 2 Insufficient cpu.
  • uniapp + vite + 使用多个 ui 库
  • LLM学习笔记2——使用Docker(Ollama+OpenWebUI)实现本地部署DeepSeek-R1-14B模型
  • 图像处理篇---基本OpenMV图像处理
  • 小程序之间实现互相跳转的逻辑
  • Ubuntu服务器设置X11服务
  • HCIA综合项目之多技术的综合应用实验
  • 大数据学习(45) - Flink基本处理函数
  • Android中获取so文件来源于哪个库
  • 轻松上手:2025年微服务教程
  • AWS上基于高德地图API验证Amazon Redshift里国内地址数据正确性的设计方案