Одна база данных переопределяет другую, когда основной компонент определен, и наоборот

#spring-boot #spring-batch

#пружинный ботинок #пружинная партия

Вопрос:

У меня есть 2 источника данных JDBC, определенных в приложении Spring Boot, которые используются в пакетном задании Spring. Однако после автоматического подключения источников данных используется только один. Используется тот, который помечен как @Primary. Если я помещу аннотацию в другой источник данных JDBC, который будет использоваться вместо этого. В двух словах, только один из источников данных JDBC когда-либо используется. Я использую Ломбок в некоторых местах, но я не уверен, играет ли это какую-то роль.

Вот источники данных:

 application.yml  symphony:  datasource:  driver-class-name: oracle.jdbc.OracleDriver  url: ...  type: com.zaxxer.hikari.HikariDataSource  username: lt;USRgt;  password: lt;PWDgt;  jndi-name: false  repo:  datasource:  driver-class-name: org.h2.Driver  url: jdbc:h2:mem:db;DB_CLOSE_DELAY=-1  username: sa  password: sa  jndi-name: false    

Вот первый источник данных:

 @Configuration  public class RepoDbConfig {    @Bean  @ConfigurationProperties("repo.datasource")  public DataSourceProperties repoDataProperties() {  return new DataSourceProperties();  }    @Bean(name = "repoDataSource")  public DataSource dataSourcerepo() {  DataSource dataSource = repoDataProperties().initializeDataSourceBuilder().type(BasicDataSource.class)  .build();  return dataSource;  }   @Bean(name = "repoJdbcTemplate")  public JdbcTemplate repoJdbcTemplate(DataSource repoDataSource) {  return new JdbcTemplate(repoDataSource);  }    }  

Вот второй источник данных:

 @Configuration  public class SymphonyDbConfig {  @Primary  @Bean  @ConfigurationProperties("symphony.datasource")  public DataSourceProperties symphonyDataSourceProperties() {  return new DataSourceProperties();  }   @Primary  @Bean(name = "symphonyDataSource")  public DataSource dataSourcesymphony() {  HikariDataSource dataSource = symphonyDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class)  .build();  return dataSource;  }   @Primary  @Bean(name = "symphonyJdbcTemplate")  public JdbcTemplate symphonyJdbcTemplate(DataSource symphonyDataSource) {  return new JdbcTemplate(symphonyDataSource);  }   }  

The JobRepository beans are configured like this:

 @Configuration  @RequiredArgsConstructor  public class JobRepositoryConfig {   final @Qualifier("repoDataSource")  DataSource repoDataSource;   @Bean("repoTransactionManager")  AbstractPlatformTransactionManager repoTransactionManager() {  return new ResourcelessTransactionManager();  }      @Bean("repoJobRepository")  public JobRepository repoJobRepository(DataSource repoDataSource) throws Exception {  JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();  jobRepositoryFactoryBean.setDataSource(repoDataSource);  jobRepositoryFactoryBean.setTransactionManager(repoTransactionManager());  jobRepositoryFactoryBean.setDatabaseType(DatabaseType.H2.getProductName());  return jobRepositoryFactoryBean.getObject();  }   @Bean("repoAppJobLauncher")  public JobLauncher careLocationAppJobLauncher(JobRepository repoJobRepository) {  SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();  simpleJobLauncher.setJobRepository(repoJobRepository);  return simpleJobLauncher;  }  }  

Finally the Batch Job beans used for the Job are configured here: The only part not shown is the launching of the job. All the required beans used are shown here:

 @Configuration  @EnableBatchProcessing  @EnableScheduling  @RequiredArgsConstructor  @Slf4j  public class CellBatchConfig {    private final JobBuilderFactory jobBuilderFactory;  @Qualifier("repoAppJobLauncher")  private final JobLauncher repoAppJobLauncher;  private final StepBuilderFactory stepBuilderFactory;    @Value("${chunk-size}")  private int chunkSize;   @Qualifier("symphonyDataSource")  final DataSource symphonyDataSource;   @Qualifier("repoDataSource")  final DataSource symphonyDataSource;   @Bean  public JdbcPagingItemReaderlt;CenterDtogt; cellItemReader(PagingQueryProvider pagingQueryProvider) {  return new JdbcPagingItemReaderBuilderlt;CenterDtogt;()  .name("cellItemReader")  .dataSource(symphonyDataSource)  .queryProvider(pagingQueryProvider)  .pageSize(chunkSize)  .rowMapper(new CellRowMapper())  .build();  }   @Bean  public PagingQueryProvider pagingQueryProvider() {  OraclePagingQueryProvider pagingQueryProvider = new OraclePagingQueryProvider();  final Maplt;String, Ordergt; sortKeys = new HashMaplt;gt;();  sortKeys.put("ID", Order.ASCENDING);  pagingQueryProvider.setSortKeys(sortKeys);  pagingQueryProvider.setSelectClause(" ID, CELL_NO, MAT_VO ");  pagingQueryProvider.setFromClause(" from pvc.cells");  return pagingQueryProvider;  }    .......  }  

Ошибка возникает в результате использования только одного из источников данных. Это приводит к тому, что используется для запроса репозитория пакетных заданий Spring, что приводит к его сбою: вот ключевая часть трассировки стека. Он пытается использовать источник данных oracle для запроса ресурсов JobRespository и в результате терпит неудачу:

 Caused by: org.springframework.jdbc.BadSqlGrammarException:   PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from   BATCH_JOB_INSTANCE   where JOB_NAME = ? and JOB_KEY = ?]; nested exception is   java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist  

Ответ №1:

В классе JobRepositoryConfig: В компоненте:

 @Bean("symphonyJobRepository")  public JobRepository symphonyJobRepository(DataSource repoDataSource) throws Exception {  JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();  jobRepositoryFactoryBean.setDataSource(repoDataSource);  jobRepositoryFactoryBean.setTransactionManager(repoTransactionManager());  jobRepositoryFactoryBean.setDatabaseType(DatabaseType.H2.getProductName());  return jobRepositoryFactoryBean.getObject();  }  

Вы не использовали переменную:

 final @Qualifier("repoDataSource") DataSource repoDataSource;  

Таким образом, Spring использует объект источника данных, который снабжен аннотацией @Primary

Комментарии:

1. Это не исправило ситуацию , смотрите правки

Ответ №2:

Я исправил это, сделав один боб основным, а также добавив квалификаторы для конкретных бобов, которые отсутствовали, что было упущением с моей стороны. Например, здесь я добавил квалификатор @:

 @Primary   @Bean(name = "symphonyDataSource")  @Qualifier("symphonyDataSource") // This was missing  public DataSource dataSourcesymphony() {  HikariDataSource dataSource = symphonyDataSourceProperties().initializeDataSourceBuilder().type(HikariDataSource.class)  .build();  return dataSource;  }