Spring: разрешить отсутствующее соединение с базой данных - PullRequest
0 голосов
/ 25 мая 2018

У меня есть проект подключения к нескольким базам данных (Oracle & SQLServer), некоторые из которых не всегда обязательны или недоступны при запуске приложения, особенно в среде разработчиков.

Я ищу способразрешить запуск приложения без подключения к базе данных.Нам требуется соединение с этими БД только при выполнении определенных задач, при которых используется промежуточная база данных, требующая определенного сетевого доступа, который не всегда доступен в 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 недоступна.
Использование встроенной базы данных не подходит для нашего варианта использования, поскольку нам не всегда нужно это соединение, и когда мыНужны ли нам конкретные данные, скопированные с производстваРазделение этого на несколько микросервисов / приложений также не допускается, так как это было бы огромным рефакто и не очень подходит для нашего варианта использования (мы объединяем данные из нескольких источников в окончательный вариант).

Есть ли простой способ разрешить это?

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Что ж, посмотрев больше на класс 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 как минимум 250 мс в нашем файле конфигурации dev, похоже, сейчас оно работает нормально.

0 голосов
/ 25 мая 2018

HikariCP предоставляет некоторые действительно хорошие параметры конфигурации , которые могут удовлетворить ваши потребности.В частности (первый в этом списке) initializationFailTimeout:

Это свойство определяет, будет ли пул "быстро проваливаться", если пул не может быть успешно заполнен при начальном соединении ...

Значение меньше нуля пропустит любую первоначальную попытку подключения, и пул будет запущен немедленно при попытке получить подключения в фоновом режиме.Следовательно, последующие попытки получить соединение могут потерпеть неудачу.

Если вы хотите решить эту проблему таким способом, то есть скрыть любые ошибки инициализации (установив отрицательное значение initializationFailTimeout), то вы 'Вам просто нужно убедиться, что у вас есть правильная логика, если БД недоступна / недоступна при получении соединения из пула.

...