首页 > 解决方案 > Spring:允许缺少数据库连接

问题描述

我有一个项目连接到多个数据库(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 不可用,则不会启动。
使用嵌入式数据库不适合我们的用例,因为我们并不总是需要这种连接,而且当我们需要从生产环境复制特定数据时。将其拆分到多个微服务/应用程序上也是不行的,因为这将是一个巨大的重构,并且并不真正适合我们的用例(我们将来自多个来源的数据汇总到一个最终的数据中)。

有没有一种简单的方法可以做到这一点?

标签: springspring-boothikaricp

解决方案


HikariCP提供了一些非常不错的配置属性,可能适合您的需求。具体来说(该列表中的第一个)initializationFailTimeout

此属性控制如果池无法通过初始连接成功播种,池是否将“快速失败”...

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

如果你想以这种方式解决你的问题,即通过隐藏任何初始化失败(通过设置一个负值initializationFailTimeout),那么你只需要确保你有正确的逻辑,以防数据库在你得到一个时无法访问/关闭来自池的连接。


推荐阅读