spring boot,

spring动态数据源

qihaiyan qihaiyan Follow Sep 16, 2020 · 2 mins read

在实际的业务场景中,我们经常会遇到需要动态配置数据源的情况,只需要修改配置,就能增加新的数据源的接入,而不需要修改程序代码,通过动态数据源技术可以实现这个目标。 具体的代码参照 示例项目 https://github.com/qihaiyan/springcamp/tree/master/spring-dynamic-datasource

一、概述

通常在用springboot开发数据库应用时,我们会在配置文件中配置好数据源,程序中指定数据源进行数据库操作。当需要新增数据源时,就需要修改程序。通过动态数据源技术,我们可以做到只修改配置就能实现新数据源的接入,无需修改代码。这样可以很大的提升开发效率,提升系统的灵活性。

二、配置文件

yml格式的配置文件支持list结构,我们可以把需要访问的数据源配置到list结构中,每个数据源指定各自的url、用户名、密码、查询语句:

spring:
  application:
    name: dynamicDatasource
dynamic-data:
  schemas:
    -
      code: dbsource1
      datasource:
        url: jdbc:h2:mem:db1;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
        username: sa
        password:
      query: |
        select 'datasource1 data'
    -
      code: dbsource2
      datasource:
        url: jdbc:h2:mem:db2;MODE=MySQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
        username: sa
        password:
      query: |
        select 'datasource2 data'

三、读取数据源配置

我们定义一个配置类DatabaseConfig 用于读取数据源的配置:

@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "dynamic-data")
public class DatabaseConfig {
    private List<DbSchema> schemas = new ArrayList<>();

    @PostConstruct
    public void init() {
        for (DbSchema current : this.getShemas()) {
            HikariConfig jdbcConfig = new HikariConfig();
            jdbcConfig.setJdbcUrl(current.getDatasource().getUrl());
            jdbcConfig.setUsername(current.getDatasource().getUsername());
            String password = current.getDatasource().getPassword();
            jdbcConfig.setPassword(password);
            try {
                HikariDataSource hikariDataSource = new HikariDataSource(jdbcConfig);
                current.setJdbcTemplate(new JdbcTemplate(hikariDataSource));
            } catch (Exception e) {
                log.error("connect to " + current.getDatasource().getUrl() + "  failed.");
                throw e;
            }
        }
    }

    @Data
    @NoArgsConstructor
    public static class DbSchema {
        private String code;
        private DataSourceProperties datasource;
        private String query;
        private JdbcTemplate jdbcTemplate;
    }
}

其中的DbSchema类对应了数据源的各项配置,包括url、用户名、密码、查询语句,另外还定义了一个JdbcTemplate,我们可以用每个数据源自己的JdbcTemplate去访问本数据源的数据。

init方法中初始化JdbcTemplate。数据库连接池采用HikariCP,这也是springboot默认使用的数据库连接池。配置文件中所有的数据库连接配置都生成一个对应的DbSchema对象,放到配置类的schemas这个list中。

通过这种方式,我们还可以实现配置文件中数据库密码的加密。配置文件中的数据库密码是加密后的密码,可以在init方法中,对current.getDatasource().getPassword()解密。这样能够提升系统的安全性,防止数据库密码通过配置文件泄漏。

四、读取各数据源的数据

当数据库连接池完成初始化后,读取数据就变的很简单,我们只需要遍历配置类中的schemas成员,针对每个schema操作JdbcTemplate就可以。

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private DatabaseConfig databaseConfig;

    @Override
    public void run(String... args) {
        databaseConfig.getSchemas().stream().filter(r -> !r.getQuery().isEmpty()).forEach(current -> {
            String result = current.getJdbcTemplate().queryForObject(
                    current.getQuery(), String.class);
            System.out.println(current.getCode() + " content: " + result);
        });
    }

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

后续如果要新增数据源,只需要在配置文件中的schemas下面新增数据源定义即可。

qihaiyan
Written by qihaiyan
业精于勤而荒于嬉,行成于思而毁于随