SpringBoot中配置多个数据源

26 篇文章 0 订阅
6 篇文章 0 订阅

说明

在Spring Boot中配置多个数据源并实现自动切换,可以通过使用AbstractRoutingDataSource和AOP(面向切面编程)的方式来实现。

下面是一个基本的步骤指南(仅供参考):

定义数据源配置

在application.properties或application.yml中定义每个数据源的连接信息。

# 主数据源 
spring.datasource.primary.url=jdbc:mysql://localhost:3306/primary_db  
spring.datasource.primary.username=root  
spring.datasource.primary.password=password  
spring.datasource.primary.driver-class-name=com.mysql.cj.jdbc.Driver  
  
 # 次数据源 
spring.datasource.secondary.url=jdbc:mysql://localhost:3306/secondary_db  
spring.datasource.secondary.username=root  
spring.datasource.secondary.password=password  
spring.datasource.secondary.driver-class-name=com.mysql.cj.jdbc.Driver

创建数据源配置类

为每个数据源创建配置相应的DataSource。

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.Map;

/**
 * 数据源配置
 * @author zq
 * @since 14:32 2024/03/20
 **/
@Configuration
public class MoreDataSourceConfig {

    /**
     * 配置主数据源 ,用于写入数据
     * @author zq
     * @since 14:27 2024/03/20
     * @return javax.sql.DataSource
     **/
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource primaryDataSource() {
        return new DruidDataSource();
    }

    /**
     * 配置从数据源 ,用于读取数据
     * @author zq
     * @since 14:27 2024/03/20
     * @return javax.sql.DataSource
     **/
    @Bean(name = "secondaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.secondary")
    public DataSource secondaryDataSource() {
        //return DataSourceBuilder.create().build();
        return new DruidDataSource();
    }
    // ...
}

创建动态数据源

实现一个继承自AbstractRoutingDataSource的动态数据源类,用来根据上下文切换数据源。

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

DataSourceContextHolder是一个用来保存当前线程的数据源键的工具类。

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

注册动态数据源

在配置类中注册动态数据源,并将所有数据源设置到动态数据源中。

@Configuration  
public class DataSourceConfig {  
  
    @Autowired  
    @Qualifier("primaryDataSource")  
    private DataSource dataSourcePrimary;  
  
    @Autowired  
    @Qualifier("secondaryDataSource")  
    private DataSource dataSourceSecondary;  
  
    @Bean(name = "dataSource")  
    public DataSource dataSource() {  
        Map<Object, Object> targetDataSources = new HashMap<>();  
        targetDataSources.put("primary", dataSourcePrimary);  
        targetDataSources.put("secondary", dataSourceSecondary);  
  
        DynamicDataSource dataSource = new DynamicDataSource();  
        dataSource.setTargetDataSources(targetDataSources);  
        dataSource.setDefaultTargetDataSource(dataSourcePrimary); // 设置默认数据源  
        return dataSource;  
    }  
  
    // ... 其他配置 ...  
}

使用AOP实现数据源自动切换

通过AOP在方法执行前设置数据源,并在方法执行后清除数据源。

@Aspect  
@Component  
public class DataSourceAspect {  
  
    @Before("@annotation(dataSource)")  
    public void switchDataSource(JoinPoint point, DataSourceSwitch dataSource) {  
        DataSourceContextHolder.setDataSourceType(dataSource.value());  
    }  
  
    @After("@annotation(dataSource)")  
    public void restoreDataSource(JoinPoint point, DataSourceSwitch dataSource) {  
        DataSourceContextHolder.clearDataSourceType();  
    }  
}

DataSourceSwitch是一个自定义注解,用来标识需要切换数据源的方法。

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

在需要切换数据源的方法上使用注解

在需要切换数据源的服务层或DAO层方法上添加@DataSourceSwitch注解,并指定数据源类型。

@Service  
public class SomeService {  
    // 调用secondary数据源的进行读取操作  
    @DataSourceSwitch("secondary")
    public void someMethodUsingSecondaryDataSource() {
     
    }

    // 默认使用primary数据源的写入操作
    @DataSourceSwitch
    public void someMethodUsingDefaultDataSource() {  
          
    }
}

事务管理说明

如果你的业务操作需要在事务中执行,确保你的事务管理器能够处理数据源的切换。这可能需要你自定义事务管理器,或者使用AOP来在事务开始之前设置正确的数据源。

注意事项

通过以上步骤,实现了在Spring Boot中配置多个数据源,并可以通过注解的方式自动切换数据源。在调用带有@DataSourceSwitch注解的方法时,AOP切面会自动将数据源切换到指定的数据源,并在方法执行完毕后恢复默认数据源。

当使用JPA时,确保每个数据源都有自己的EntityManagerFactory和TransactionManager。
考虑到线程安全问题,确保你的数据源切换逻辑是线程安全的
数据源切换通常用于读取和写入操作分离的场景,或者当你有多个独立的数据库需要访问时。确保不要过度使用,因为它可能增加复杂性和出错的可能性。

请注意,这是一个高级功能,并且可能会引入额外的复杂性和潜在的问题。在生产环境中使用之前,请确保彻底测试你的实现

1. 添加多个数据源配置文件 在 `src/main/resources` 目录下新建一个 `application-xxx.yml` 文件,其 `xxx` 用于区分不同数据源配置。例如,如果你要配置一个名为 `primary` 的数据源和一个名为 `secondary` 的数据源,那么你需要创建两个配置文件: application-primary.yml: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/primary_db username: root password: root ``` application-secondary.yml: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/secondary_db username: root password: root ``` 2. 配置数据源 在 `application.yml` 文件配置数据源相关的信息,包括默认数据源和其他数据源的信息。例如: ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/primary_db username: root password: root driver-class-name: com.mysql.jdbc.Driver # 配置其他数据源 primary: url: jdbc:mysql://localhost:3306/primary_db username: root password: root driver-class-name: com.mysql.jdbc.Driver secondary: url: jdbc:mysql://localhost:3306/secondary_db username: root password: root driver-class-name: com.mysql.jdbc.Driver ``` 3. 创建数据源 在 `@Configuration` 注解的类创建数据源。使用 `@Primary` 注解标注默认数据源,其他数据源使用一个独立的方法创建。例如: ```java @Configuration public class DataSourceConfig { @Primary @Bean(name = "dataSource") @ConfigurationProperties(prefix = "spring.datasource") public DataSource dataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } } ``` 4. 配置 JdbcTemplate 在 `@Configuration` 注解的类配置 `JdbcTemplate`。使用 `@Qualifier` 注解指定数据源。例如: ```java @Configuration public class JdbcTemplateConfig { @Primary @Bean(name = "jdbcTemplate") public JdbcTemplate jdbcTemplate(@Qualifier("dataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = "primaryJdbcTemplate") public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } @Bean(name = "secondaryJdbcTemplate") public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource dataSource) { return new JdbcTemplate(dataSource); } } ``` 5. 使用 JdbcTemplate 在需要使用 JdbcTemplate 的地方,使用 `@Autowired` 注解注入 JdbcTemplate。使用 `@Qualifier` 注解指定数据源。例如: ```java @Service public class UserService { @Autowired @Qualifier("primaryJdbcTemplate") private JdbcTemplate primaryJdbcTemplate; @Autowired @Qualifier("secondaryJdbcTemplate") private JdbcTemplate secondaryJdbcTemplate; public List<User> getAllUsersFromPrimary() { return primaryJdbcTemplate.query("SELECT * FROM user", new BeanPropertyRowMapper<>(User.class)); } public List<User> getAllUsersFromSecondary() { return secondaryJdbcTemplate.query("SELECT * FROM user", new BeanPropertyRowMapper<>(User.class)); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值