bugfix> spring > 投稿

複数のデータベース(OracleおよびSQLServer)に接続するプロジェクトがありますが、そのうちのいくつかは、特に開発環境では、アプリケーションの起動時に必ずしも必須ではなく、利用できません。

データベース接続なしでアプリケーションをすぐに起動できるようにする方法を探しています。特定のタスクを実行するときに、これらのDBへの接続のみが必要です。特定のタスクでは、devで常に使用できるとは限らない特定のネットワークアクセスを必要とするステージングデータベースを使用します。

ここでは、Oracle接続(特定のネットワーク下にあるもの)を使用しています。

アプリケーションの起動を許可する構成がありましたが、HikariDataSourceの誤ったキャストのために、テストの実行時にエラーをスローしていました。

@Configuration
@EnableJpaRepositories(
        basePackages = "com.bar.foo.repository.oracle",
        entityManagerFactoryRef = "oracleEntityManager",
        transactionManagerRef = "oracleTransactionManager"
)
public class OracleConfiguration {
private final Logger            log = LoggerFactory.getLogger(this.getClass());
@Inject
private Environment             environment;
@Value("${spring.datasource.oracle.ddl-auto:none}")
private String hibernateddlAuto;
@Value("${spring.datasource.oracle.dialect:org.hibernate.dialect.Oracle10gDialect}")
private String hibernateDialect;
@Bean
@Primary
@ConfigurationProperties("spring.datasource.oracle")
public DataSourceProperties oracleDataSourceProperties() {
    return new DataSourceProperties();
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource.hikari")
public DataSource oracleDataSource() {
    HikariDataSource ds = (HikariDataSource) oracleDataSourceProperties().initializeDataSourceBuilder().build();
    ds.setPoolName(environment.getProperty("spring.datasource.oracle.poolName"));
    return ds;
}

@Bean
@Primary
public LocalContainerEntityManagerFactoryBean oracleEntityManager() {
    LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
    em.setPackagesToScan("com.bar.foo.domain.oracle");
    HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
    em.setJpaVendorAdapter(vendorAdapter);
    HashMap<String, Object> properties = new HashMap<>();
    properties.put("hibernate.ddl-auto", hibernateddlAuto);
    properties.put("hibernate.dialect", hibernateDialect);
    em.setJpaPropertyMap(properties);
    em.setDataSource(oracleDataSource());
    return em;
}
@Primary
@Bean
public PlatformTransactionManager oracleTransactionManager() {
    JpaTransactionManager transactionManager

     = new JpaTransactionManager();
    transactionManager.setEntityManagerFactory(
            oracleEntityManager().getObject());
    return transactionManager;
}
}

この構成を移動して、HikariConfigを次のように拡張しました。

@Configuration
@EnableJpaRepositories(
    basePackages = "com.bar.foo.repository.oracle",
    entityManagerFactoryRef = "oracleEntityManager",
    transactionManagerRef = "oracleTransactionManager"
)
@ConfigurationProperties("spring.datasource.oracle")
public class OracleConfiguration extends HikariConfig{

    @Bean
    @Primary
    public DataSource oracleDataSource() {
      return new HikariDataSource(this);
    }
    @Bean
    @Primary
public LocalContainerEntityManagerFactoryBean oracleEntityManager() {
  LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
  em.setPackagesToScan("com.bar.foo.domain.oracle");
  HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
  em.setJpaVendorAdapter(vendorAdapter);
  HashMap<String, Object> properties = new HashMap<>();
      properties.put("hibernate.ddl-auto", hibernateddlAuto);
      properties.put("hibernate.dialect", hibernateDialect);
  em.setJpaPropertyMap(properties);
  em.setDataSource(oracleDataSource());
  return em;
}
@Bean
@Primary
public PlatformTransactionManager oracleTransactionManager() {
  JpaTransactionManager transactionManager
    = new JpaTransactionManager();
  transactionManager.setEntityManagerFactory(
    oracleEntityManager().getObject());
  return transactionManager;
}

Oracle DBが利用できない場合は起動しません。
埋め込みDBを使用することは、この接続を常に必要とするわけではなく、必要な場合は実稼働環境から複製された特定のデータを必要とするため、ユースケースに適合しません。 これを複数のマイクロサービス/アプリケーションに分割することも大したことではありません。実際の使用例には適合しません(複数のソースからのデータを最終的なものに集約します)。

これを許可する簡単な方法はありますか?

回答 2 件
  • HikariCP  ニーズに合った本当に素晴らしい設定プロパティを提供します。具体的には(そのリストの最初のもの) initializationFailTimeout

    This property controls whether the pool will "fail fast" if the pool cannot be seeded with an initial connection successfully...

    A value less than zero will bypass any initial connection attempt, and the pool will start immediately while trying to obtain connections in the background. Consequently, later efforts to obtain a connection may fail.

    この方法で問題を解決したい場合、つまり、初期化の失敗を隠して(負の initializationFailTimeout を設定することで)  値)、プールから接続を取得するときにDBにアクセスできない/ダウンした場合に備えて、正しいロジックを確保する必要があります。

  • さて、HikariConfigクラスをさらに調べた後、 初期化失敗タイムアウト

    * @param initializationFailTimeout the number of milliseconds before the
    *        pool initialization fails, or 0 to validate connection setup but continue with
    *        pool start, or less than zero to skip all initialization checks and start the
    *        pool without delay.
    
    

    ゼロ以下に設定すると、アプリケーションの起動が可能になりますが、以前よりもはるかに長くかかります。ゼロ以下に設定しても、2つの接続タイムアウトを待つことを妨げません。

    また、dev構成ファイルでconnectionTimeoutを最小250msに設定しましたが、今のところ正常に機能しているようです。

あなたの答え