Spring:允许缺少数据库连接

时间:2018-05-25 14:35:30

标签: spring spring-boot hikaricp

我有一个项目连接到多个数据库(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不可用,则无法启动 使用嵌入式数据库不适合我们的用例,因为我们并不总是需要这种连接,当我们这样做时,我们需要从Production复制特定数据。 在多个微服务/应用程序上拆分它也是一个禁忌,因为它将是一个巨大的重构,并不真正适合我们的用例(我们将来自多个源的数据汇总到最后一个)。

有一种简单的方法可以允许吗?

3 个答案:

答案 0 :(得分:1)

HikariCP提供了一些可能符合您需求的nice configuration properties。具体而言(该列表中的第一个)initializationFailTimeout

  

此属性控制池是否会快速失败&#34;如果游泳池   无法成功通过初始连接播种...

     

一个值   小于零将绕过任何初始连接尝试,并且   池将在尝试获取连接时立即启动   背景。因此,以后努力获得连接可能   失败。

如果你想以这种方式解决你的问题,即隐藏任何初始化失败(通过设置负initializationFailTimeout值),那么你只需要确保你有正确的逻辑以防万一从池中获取连接时,DB无法访问/关闭。

答案 1 :(得分: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,它现在似乎正常工作。

答案 2 :(得分:0)

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

spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect

使用该设置,我没有像使用initializationFailTimeout设置时那样缓慢地启动应用程序。