Spring:允许缺少数据库连接

问题描述 投票:2回答:3

我有一个连接到多个数据库(Oracle和SQLServer)的项目,其中一些并非总是强制性的,启动应用程序时也不可用-特别是在开发环境中。

我正在寻找一种允许应用程序在没有数据库连接的情况下启动的方法。在执行特定任务时,我们仅需要与这些数据库的连接,这些任务使用的临时数据库需要特定的网络访问权限,而开发人员并不总是可用的。

在这里,使用我们的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将不适合我们的用例,因为我们并不总是需要此连接,并且当我们这样做时,我们需要从Production复制特定的数据。将其拆分到多个微服务/应用程序上也是不可行的,因为这将是一个巨大的事实,并且实际上不适合我们的用例(我们将来自多个源的数据聚合到最终一个)。

有没有简单的方法可以允许这种情况?

spring spring-boot hikaricp
3个回答
2
投票

HikariCP提供了一些确实适合您需要的nice configuration properties。具体来说(该列表中的第一个)initializationFailTimeout

[此属性控制池是否在池中快速失败”无法成功建立初始连接的种子...

一个值小于零将绕过任何初始连接尝试,并且尝试在背景。因此,以后可能会尝试获得连接失败。

[如果您想通过这种方式解决问题,即隐藏任何初始化失败(通过设置负initializationFailTimeout值),则只需确保您具有正确的逻辑,以防数据库无法访问/当您从池中获得连接时关闭。


0
投票

嗯,在看了更多HikariConfig类之后,我发现了InitializationFailTimeout指出

* @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.

将其设置为零或以下将允许应用程序启动,但是它花费的时间比以前长得多,而将其设置为零以下不会阻止它等待两个连接超时。

我最终还在我们的开发配置文件上将connectionTimeout设置为最小250ms,现在看来工作正常。


0
投票

另一种解决方案是设置以下参数:

spring.datasource.continue-on-error=true
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect

使用这些设置,我没有像使用initializationFailTimeout设置时那样启动应用程序时出现任何缓慢。

© www.soinside.com 2019 - 2024. All rights reserved.