当 Primary Bean 被定义时,一个数据库会覆盖另一个,反之亦然

One Database overrides the other when Primary Bean is defined on and vice versa

我在 Spring 启动应用程序中定义了 2 个 JDBC 数据源,用于 Spring 批处理作业。然而,在自动装配数据源之后,只有一个被使用。使用的是注解为@Primary 的那个。如果我将注释放在另一个 JDBC 数据源上,则会被使用。简而言之,只有一个 JDBC 数据源被使用。我在某些地方使用 Lombok,但我不确定它是否起作用。

这里是数据源:

application.yml

symphony:
   datasource:
   driver-class-name: oracle.jdbc.OracleDriver
   url: ...
   type: com.zaxxer.hikari.HikariDataSource
   username: <USR>
   password: <PWD>
   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);
        }

    }

JobRepository bean 配置如下:

        @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;
            }
        }

最后,用于作业的批处理作业 bean 在此处配置:唯一未显示的部分是作业的启动。此处显示了所有需要使用的 bean:

@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 JdbcPagingItemReader<CenterDto> cellItemReader(PagingQueryProvider pagingQueryProvider) {
                return new JdbcPagingItemReaderBuilder<CenterDto>()
                        .name("cellItemReader")
                        .dataSource(symphonyDataSource)
                        .queryProvider(pagingQueryProvider)
                        .pageSize(chunkSize)
                        .rowMapper(new CellRowMapper())
                        .build();
            }

            @Bean
            public PagingQueryProvider pagingQueryProvider() {
                OraclePagingQueryProvider pagingQueryProvider = new OraclePagingQueryProvider();
                final Map<String, Order> sortKeys = new HashMap<>();
                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

在 class 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注解注解的DataSource对象

我通过将一个 bean 设为主要 bean 并在缺失的特定 bean 上添加限定符来修复它,这是我的疏忽。例如,这里我添加了@Qualifier:

        @Primary

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