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

SpringBoot 项目配置动态数据源

目录

    • 一、前言
    • 二、操作
      • 1、引入依赖
      • 2、配置默认数据库 1
      • 3、定义数据源实体和 Repository
      • 4、定义动态数据源
      • 5、配置数据源
      • 6、定义切换数据源注解
      • 7、定义切面类
      • 8、使用注解切换数据源

一、前言

通过切面注解方式根据不同业务动态切换数据库

二、操作

1、引入依赖

<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>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>com.zaxxer</groupId>
        <artifactId>HikariCP</artifactId>
    </dependency>
</dependencies>

2、配置默认数据库 1

  • 在 application.properties 或 application.yml 配置数据库 1 信息:
spring.datasource.url=jdbc:mysql://localhost:3306/db1
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3、定义数据源实体和 Repository

  • 数据源实体 DataSourceConfig.java:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class DataSourceEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String url;
    private String username;
    private String password;
    private String driverClassName;
    private String dataSourceKey; // 新增字段

    // Getters 和 Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public void setDriverClassName(String driverClassName) {
        this.driverClassName = driverClassName;
    }

    public String getDataSourceKey() {
        return dataSourceKey;
    }

    public void setDataSourceKey(String dataSourceKey) {
        this.dataSourceKey = dataSourceKey;
    }
}
  • Repository 接口 DataSourceConfigRepository.java:
import org.springframework.data.jpa.repository.JpaRepository;

public interface DataSourceConfigRepository extends JpaRepository<DataSourceEntity, Long> {
}

4、定义动态数据源

  • 动态数据源上下文持有者 DynamicDataSourceContextHolder.java:
public class DynamicDataSourceContextHolder {
    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();
    }
}
  • 动态数据源类 DynamicDataSource.java:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceKey();
    }
}

5、配置数据源

import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Configuration
public class DataSourceConfig {
    @Autowired
    private DataSourceConfigRepository dataSourceConfigRepository;

    @Primary
    @Bean
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();

        // 从数据库 1 的 datasource 表加载所有数据源
        List<DataSourceEntity> dataSourceConfigs = dataSourceConfigRepository.findAll();
        for (DataSourceEntity config : dataSourceConfigs) {
            HikariDataSource dataSource = new HikariDataSource();
            dataSource.setJdbcUrl(config.getUrl());
            dataSource.setUsername(config.getUsername());
            dataSource.setPassword(config.getPassword());
            dataSource.setDriverClassName(config.getDriverClassName());
            targetDataSources.put(config.getId().toString(), dataSource);
            if ("db1".equals(config.getDataSourceKey())) { // 假设表中有一个字段表示数据源的 key
                dynamicDataSource.setDefaultTargetDataSource(dataSource);
            }
        }

        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }
}

6、定义切换数据源注解

import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSourceSwitch {
    String value() default "db1";
}

7、定义切面类

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;

@Aspect
@Component
public class DataSourceSwitchAspect {
    @Autowired
    private DataSourceConfigRepository dataSourceConfigRepository;

    @Before("@annotation(com.example.annotation.DataSourceSwitch)")
    public void before(JoinPoint point) {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSourceSwitch dataSourceSwitch = method.getAnnotation(DataSourceSwitch.class);
        if (dataSourceSwitch != null) {
            String dataSourceKey = dataSourceSwitch.value();
            List<DataSourceEntity> dataSourceConfigs = dataSourceConfigRepository.findAll();
            for (DataSourceConfig config : dataSourceConfigs) {
                if (dataSourceKey.equals(config.getDataSourceKey())) {
                    DynamicDataSourceContextHolder.setDataSourceKey(config.getId().toString());
                    break;
                }
            }
        }
    }

    @After("@annotation(com.example.annotation.DataSourceSwitch)")
    public void after(JoinPoint point) {
        DynamicDataSourceContextHolder.clearDataSourceKey();
    }
}

8、使用注解切换数据源

import com.example.annotation.DataSourceSwitch;
import com.example.entity.User;
import com.example.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    @DataSourceSwitch("db1")
    public List<User> getUsersFromDb1() {
        return userRepository.findAll();
    }

    @DataSourceSwitch("db2") // 假设 db2 是从 datasource 表获取的数据源 key
    public List<User> getUsersFromDb2() {
        return userRepository.findAll();
    }
}

相关文章:

  • 【C++篇】树影摇曳,旋转无声:探寻AVL树的平衡之道
  • Apache Logic4j 库反序列化漏洞复现与深度剖析
  • 【蓝桥杯集训·每日一题2025】 AcWing 6135. 奶牛体检 python
  • HarmonyOS学习第3天: 环境搭建开启鸿蒙开发新世界
  • java练习(35)
  • 如何用好 DeepSeek 工具:入门指南
  • 【CSP/信奥赛通关课(一):C++语法基础】
  • PrimeTime:工具简介
  • 算法模板(二分法开区间模板,二分法闭区间模板)
  • 【华三】STP的角色选举(一文讲透)
  • 市场趋势中突破确认的多维度判断方法
  • 【简历优化】性能调优 — 编程性能调优篇
  • Linux远程kill进程及$处理
  • java练习(36)
  • 如何在 React 中测试高阶组件?
  • python: SQLAlchemy (ORM) Simple example using mysql in Ubuntu 24.04
  • Docker挂载数据显式挂载和隐式挂载的区别
  • DeepSeek掘金——VSCode 接入DeepSeek V3大模型,附使用说明
  • ubuntu ffmpeg 安装踩坑
  • Liunx(CentOS-6-x86_64)系统安装MySql(5.6.50)
  • 超级工程网站建设上海中心大厦/沈阳网站建设
  • 公司网站域名怎么加www./太原关键词优化服务
  • 代刷开通建设网站/武汉seo 网络推广
  • 磁力天堂/新乡seo推广
  • 平面设计教程视频全集免费/网络优化的流程
  • 做外贸网站建设/百度收录平台