Spring Bootで複数DBに接続する際の注意点

技術Spring

概要

Spring Boot で複数 DB に接続する際に少し詰まったので、備忘録代わりに書く。

詳細

今回、MySQLとPostgreSQLの二つを一モジュールから繋がないといけないケースを想定する。

JDBCとJPAでどのように実現できるかを検証した。(プロジェクト)

JDBC

まずは設定ファイル(YAML/Property file)にDBの設定情報を指定する。

spring:
  datasource:
    mysql:
      jdbc-url: jdbc:mysql://localhost:3306/sample_db
      username: dbuser
      password: userpass
      driver-class-name: com.mysql.cj.jdbc.Driver
    postgresql:
      jdbc-url: jdbc:postgresql://localhost:5432/sample_db
      username: dbuser
      password: userpass
      driver-class-name: org.postgresql.Driver

一つだけDBに繋ぐ際とは異なり、spring.datasource以下に各種パラメータを設定するのではなく、繋ぐDBごとに設定を行うのが大きな変更点。(今回なら、spring.datasource.mysql/spring.datasource.postgresql

そして、設定ファイルを読み込みDatasourceを構成する。

*一つだけ繋ぐ場合、spring.datasource以下にパラメータを定義することで、自動的にDatasourceを構成してくれる (DataSourceProperties.java)

@Configuration
public class JdbcDataSourceConfig {

    @Bean("mysqlJdbcDataSource")
    @ConfigurationProperties("spring.datasource.mysql")
    @Primary
    public DataSource mysqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean("postgresqlJdbcDataSource")
    @ConfigurationProperties("spring.datasource.postgresql")
    public DataSource postgresqlDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean("mysql")
    public JdbcTemplate createMysqlDataSource(@Qualifier("mysqlJdbcDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean("postgresql")
    public JdbcTemplate createPostgresqlDataSource(@Qualifier("postgresqlJdbcDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }
}

JPA

設定ファイルに関してはJDBCと同様に定義。

そしてDatasourceの定義に関しても独自でやるところは同様だが、大きく変わるところは、

  • transactionManagerをもう一つのDBと異なるユニットで定義
  • entityが格納されたパッケージの指定(基本的にはもう一つのDBと異なるEntityのはずなので、違ったパッケージを指定することが多いかも)
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = "com.example.multipledb.repository.mysql",
        entityManagerFactoryRef = "mysqlEntityManagerFactory",
        transactionManagerRef = "mysqlTransactionManager"
)
public class MysqlJpaDataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.mysql")
    public DataSource mysqlJpaDataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory(
            EntityManagerFactoryBuilder builder,
            @Qualifier("mysqlJpaDataSource") DataSource dataSource
    ) {
        return builder
                .dataSource(dataSource)
                .packages("com.example.multipledb.entity.mysql")
                .persistenceUnit("mysqlTransactionManager")
                .build();
    }

    @Bean
    public JpaTransactionManager mysqlTransactionManager(
            @Qualifier("mysqlEntityManagerFactory") LocalContainerEntityManagerFactoryBean mysqlEntityManagerFactory
    ) {
        return new JpaTransactionManager(Objects.requireNonNull(mysqlEntityManagerFactory.getObject()));
    }
}

まとめ

基本的には、それぞれ繋ぎたいDBの設定を書いて、独自でConfigを構成するだけ(ただ、JDBCに関しては自動で設定してくれることもあり、若干戸惑うかも)

参考記事