Spring Boot 設定多資料來源

2022-11-30 15:01:10

Spring Boot 設定多資料來源

作者:Grey

原文地址:

部落格園:Spring Boot 設定多資料來源

CSDN:Spring Boot 設定多資料來源

說明

本文主要介紹了 Spring Boot 下如何設定多資料來源。

環境和版本

Java 版本:17

Spring Boot 版本:3.0.0

資料庫:H2

注:本範例基於 JdbcTemplate,如果使用 JPA,Hiberante 或者 Mybatis 等,方法類似。

程式碼說明

首先,設定兩個資料來源,這裡我們基於 H2 設定了兩個簡單資料來源,由於 H2 是記憶體資料庫,無需手動新建

foo.datasource.url=jdbc:h2:mem:foo
foo.datasource.username=sa
foo.datasource.password=
foo.datasource.driver-class-name=org.h2.Driver
bar.datasource.url=jdbc:h2:mem:bar
bar.datasource.username=sa
bar.datasource.password=
bar.datasource.driver-class-name=org.h2.Driver

接下來在 resources 新建一個 db 資料夾,裡面存兩個資料庫的初始化指令碼

schema.sql

DROP TABLE IF EXISTS USER_INFO;

CREATE TABLE USER_INFO
(
    id        INT AUTO_INCREMENT PRIMARY KEY,
    user_name VARCHAR(250) NOT NULL,
    email     VARCHAR(250) DEFAULT NULL
);

foo 資料來源的初始化資料 foo-data.sql

INSERT INTO
    USER_INFO (user_name, email)
VALUES
    ('grey-foo', '[email protected]'),
    ('jack-foo', '[email protected]');

bar 資料來源的初始化資料 bar-data.sql

INSERT INTO USER_INFO (user_name, email)
VALUES ('grey-bar', '[email protected]'),
       ('jack-bar', '[email protected]');

指令碼和資料來源設定好以後,接下來要準備兩個資料來源的設定類資訊,以任意一個資料來源的設定類資訊為例(另外一個同理)

foo 資料來源的設定資訊如下

@Configuration
@ConfigurationProperties(prefix = "foo.datasource")
@Slf4j
public class FooDataSourceConfig {

  @Bean
  public PlatformTransactionManager fooTxManager(DataSource fooDataSource) {
    return new DataSourceTransactionManager(fooDataSource);
  }

  @Bean
  public DataSourceProperties fooDataSourceProperties() {
    return new DataSourceProperties();
  }

  @Bean
  @Primary
  public DataSource fooDataSource() {
    DataSourceProperties dataSourceProperties = fooDataSourceProperties();
    // schema init
    DatabasePopulator databasePopulator =
        new ResourceDatabasePopulator(
            new ClassPathResource("db/schema.sql"), new ClassPathResource("db/foo-data.sql"));
    DataSource ds = dataSourceProperties.initializeDataSourceBuilder().build();
    DatabasePopulatorUtils.execute(databasePopulator, ds);
    log.info("foo datasource: {}", dataSourceProperties.getUrl());
    return ds;
  }

  @Bean
  @Primary
  public JdbcTemplate fooJdbcTemplate(@Qualifier("fooDataSource") DataSource dataSource) {
    return new JdbcTemplate(dataSource);
  }
}

需要注意的點,@Primary引數定義了該資料來源是主資料來源,也就是說,呼叫資料來源的時候,如果沒有指定名稱預設就是用這個資料來源。

fooDataSource中,定義了初始化指令碼的位置

 DatabasePopulator databasePopulator =
        new ResourceDatabasePopulator(
            new ClassPathResource("db/schema.sql"), new ClassPathResource("db/foo-data.sql"));

另外一個 BarDataSourceConfig 同理。

完成上述設定後,在啟動類中注入這兩個資料來源對應的JdbcTemplate

@SpringBootApplication
@Slf4j
public class SpringMultiDatasourceApplication implements CommandLineRunner {
  private final JdbcTemplate fooTemplate;
  private final JdbcTemplate barTemplate;
  private final JdbcTemplate defaultTemplate;

  public SpringMultiDatasourceApplication(
      @Qualifier("fooJdbcTemplate") JdbcTemplate fooTemplate,
      @Qualifier("barJdbcTemplate") JdbcTemplate barTemplate,
      JdbcTemplate defaultTemplate) {
    this.fooTemplate = fooTemplate;
    this.barTemplate = barTemplate;
    this.defaultTemplate = defaultTemplate;
  }

  @Override
  public void run(String... args) throws Exception {
    fooTemplate.queryForList("SELECT * FROM USER_INFO").forEach(row -> log.info(row.toString()));
    log.info("----");
    barTemplate.queryForList("SELECT * FROM USER_INFO").forEach(row -> log.info(row.toString()));
    log.info("----");
    defaultTemplate
        .queryForList("SELECT * FROM USER_INFO")
        .forEach(row -> log.info(row.toString()));
  }
  
  public static void main(String[] args) {
    SpringApplication.run(SpringMultiDatasourceApplication.class, args);
  }

}

本範例中,注入了三個JdbcTemplate,其中兩個通過@Qualifier指定了名稱,還有一個defaultTemplate並未指定名稱,所以取的就是有@Primary註解的JdbcTemplate

執行主函數,列印出如下資訊

{ID=1, USER_NAME=grey-foo, [email protected]}
{ID=2, USER_NAME=jack-foo, [email protected]}
----
{ID=1, USER_NAME=grey-bar, [email protected]}
{ID=2, USER_NAME=jack-bar, [email protected]}
----
{ID=1, USER_NAME=grey-foo, [email protected]}
{ID=2, USER_NAME=jack-foo, [email protected]}

可以看到效果,預設的JdbcTemplate取的是 foo 資料來源的資訊。

完整程式碼

spring-multi-datasource

參考資料

Spring Boot 2 Multiple Datasources initialize schema

Configure and Use Multiple DataSources in Spring Boot