【Java】Spring Boot配置动态数据源

文章介绍了如何在SpringBoot中配置和使用动态数据源,通过实现AbstractRoutingDataSource来切换数据源,并展示了如何创建动态数据源配置类、服务类以及数据源生成器。数据源的动态添加和切换主要依赖于DynamicDataSourceService,该服务类使用线程本地存储来实现不同请求的数据源隔离。此外,还提供了一个根据配置文件自动生成数据源的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringBoot配置动态数据源

一、动态多数据源的配置

1.1 创建动态数据源

通过实现Spring提供的AbstractRoutingDataSource类,可以实现自己的数据源选择逻辑,从而可以实现数据源的动态切换。

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Value("${spring.datasource.default-db-key}")
    private String defaultDbKey;·

    @Override
    protected Object determineCurrentLookupKey() {
        String currentDb = DynamicDataSourceService.currentDb();
        if (currentDb == null) {
            return defaultDbKey;
        }
        return currentDb;
    }
}

1.2 创建动态数据源配置类

跟配置静态多数据源一样,需要手动配置下面的三个 Bean,只不过DynamicDataSource类的targetDataSources是空的。

@Configuration
public class DynamicDataSourceConfig {
    /**
     * 动态数据源
     */
    @Bean
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        dataSource.setTargetDataSources(targetDataSources);
        return dataSource;
    }

    /**
     * 会话工厂
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean() throws IOException {
        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
        sqlSessionFactoryBean.setConfiguration(configuration);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath*:/repository/*.xml"));
        return sqlSessionFactoryBean;
    }

    /**
     * 事务管理器
     */
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dynamicDataSource());
    }
    
}

1.3 创建动态数据源服务类

这是一个比较核心的工具类,提供了一些静态方法从而可以实现一些功能,包括:
动态添加数据源切换数据源重置数据源获取数据源
在 DynamicDataSource 类中,就是调用了 DynamicDataSourceService 类的 switchDb
方法实现的数据源选择。
通过查看下面的代码就能看出来使用线程本地的技术实现的多个请求数据源互不相干。

@Slf4j
public class DynamicDataSourceService {
    private static final Map<Object, Object> dataSources = new HashMap<>();
    private static final ThreadLocal<String> dbKeys = ThreadLocal.withInitial(() -> null);

    /**
     * 动态添加一个数据源
     *
     * @param name       数据源的key
     * @param dataSource 数据源对象
     */
    public static void addDataSource(String name, DataSource dataSource) {
        DynamicDataSource dynamicDataSource = App.context.getBean(DynamicDataSource.class);
        dataSources.put(name, dataSource);
        dynamicDataSource.setTargetDataSources(dataSources);
        dynamicDataSource.afterPropertiesSet();

        log.info("addDataSource 添加了数据源:{}", name);
    }

    /**
     * 切换数据源
     */
    public static void switchDb(String dbKey) {
        dbKeys.set(dbKey);
        log.info("switchDb 切换数据源:{}", dbKey);
    }

    /**
     * 重置数据源
     */
    public static void resetDb() {
        dbKeys.remove();
        log.info("resetDb 重置数据源");
    }

    /**
     * 获取当前数据源
     */
    public static String currentDb() {
    	log.info("currentDb 获取当前数据源");
        return dbKeys.get();
    }
}

至此,动态多数据源的配置就完成了,只需要编写数据源生成的逻辑,在程序运行时调用 addDataSource 方法即可将数据源动态添加到上下文中,并支持动态切换。

下面简单介绍一下基于配置文件的数据源生成。

二、数据源生成器

2.1 自定义了一个数据源生成器接口用于定义动态生成数据源的要求。

public interface DataSourceProvider {
    List<DataSource> provide();
}

2.2 然后编写了一个根据配置文件提供数据源并配置的实现类。

@Component
@ConfigurationProperties(prefix = "spring.datasource.hikari")
public class YmlDataSourceProvider implements DataSourceProvider {

    private List<Map<String, DataSourceProperties>> dataSources;

    private DataSource buildDataSource(DataSourceProperties prop) {
        DataSourceBuilder<?> builder = DataSourceBuilder.create();
        builder.driverClassName(prop.getDriverClassName());
        builder.username(prop.getUsername());
        builder.password(prop.getPassword());
        builder.url(prop.getJdbcUrl());
        return builder.build();
    }

    @Override
    public List<DataSource> provide() {
        List<DataSource> res = new ArrayList<>();
        dataSources.forEach(map -> {
            Set<String> keys = map.keySet();
            keys.forEach(key -> {
                DataSourceProperties properties = map.get(key);
                DataSource dataSource = buildDataSource(properties);
                DynamicDataSourceService.addDataSource(key, dataSource);
            });
        });
        return res;
    }

    @PostConstruct
    public void init() {
        provide();
    }

    public List<Map<String, DataSourceProperties>> getDataSources() {
        return dataSources;
    }

    public void setDataSources(List<Map<String, DataSourceProperties>> dataSources) {
        this.dataSources = dataSources;
    }
}

看一下对应的配置文件内容:

spring:
  datasource:
    default-db-key: db0
    hikari:
      data-sources:
        - db0:
            jdbc-url: jdbc:mysql://127.0.0.1:3306/codingcea
            username: codingce
            password: 1234567890
            driver-class-name: com.mysql.cj.jdbc.Driver
        - db1:
            jdbc-url: jdbc:mysql://127.0.0.1:3306/codingceb
            username: codingce
            password: 1234567890
            driver-class-name: com.mysql.cj.jdbc.Driver

这样就实现了应用启动时自动将配置文件中的数据源配置读取并生成数据源注册到上下文中;
当然也可以有其他的实现,比如从数据库读取并配置,或者通过接口请求的方式生成都可以,只要实现自己的DataSourceProvider就可以。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

后端码匠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值