【问题标题】:SpringBoot app. accessing 2 DataSources using JdbcTemplateSpringBoot 应用程序。使用 JdbcTemplate 访问 2 个数据源
【发布时间】:2018-07-26 00:22:18
【问题描述】:

我有一个 SpringBoot 应用程序。必须访问不同的数据源才能将数据从 1 导出到另一个(1 个本地数据源和另一个远程数据源)

这就是我的 persistenceConfig 的样子

public class PersistenceConfig {

    @Bean
    public  JdbcTemplate localJdbcTemplate() {
        return new JdbcTemplate(localDataSource());
    }

    @Bean
    public  JdbcTemplate remoteJdbcTemplate() {
        return new JdbcTemplate(remoteDataSource());
    }



    @Bean
    public DataSource localDataSource(){

        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(getLocalDbPoolSize());
        config.setMinimumIdle(5);
        config.setDriverClassName(getLocalDbDriverClassName());
        config.setJdbcUrl(getLocalDbJdbcUrl());
        config.addDataSourceProperty("user", getLocalDbUser());
        config.addDataSourceProperty("password", getLocalDbPwd());

        return new HikariDataSource(config);
    }


    @Bean
    public DataSource remoteDataSource(){

        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(getRemoteDbPoolSize());
        config.setMinimumIdle(5);
        config.setDriverClassName(getRemoteDbDriverClassName());
        config.setJdbcUrl(getRemoteDbJdbcUrl());
        config.addDataSourceProperty("user", getRemoteDbUser());
        config.addDataSourceProperty("password", getRemoteDbPwd());

        return new HikariDataSource(config);
    }
}

但是当我初始化我的应用程序时,我收到了这个错误:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.sql.DataSource' available: expected single matching bean but found 2: localDataSource,remoteDataSource

我也尝试过使用合格的bean,如下:

@Bean(name = "localJdbcTemplate")
    public  JdbcTemplate localJdbcTemplate() {
        return new JdbcTemplate(localDataSource());
    }


    @Bean(name = "remoteJdbcTemplate")
    public  JdbcTemplate remoteJdbcTemplate() {
        return new JdbcTemplate(remoteDataSource());
    }



    @Bean(name = "localDataSource")
    public DataSource localDataSource(){

        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(getLocalDbPoolSize());
        config.setMinimumIdle(5);
        config.setDriverClassName(getLocalDbDriverClassName());
        config.setJdbcUrl(getLocalDbJdbcUrl());
        config.addDataSourceProperty("user", getLocalDbUser());
        config.addDataSourceProperty("password", getLocalDbPwd());

        return new HikariDataSource(config);
    }


    @Bean(name = "remoteDataSource")
    public DataSource remoteDataSource(){

        HikariConfig config = new HikariConfig();
        config.setMaximumPoolSize(getRemoteDbPoolSize());
        config.setMinimumIdle(5);
        config.setDriverClassName(getRemoteDbDriverClassName());
        config.setJdbcUrl(getRemoteDbJdbcUrl());
        config.addDataSourceProperty("user", getRemoteDbUser());
        config.addDataSourceProperty("password", getRemoteDbPwd());

        return new HikariDataSource(config);
    }

但后来我得到了另一个错误:

A component required a bean of type 'org.springframework.transaction.PlatformTransactionManager' that could not be found.
    - Bean method 'transactionManager' not loaded because @ConditionalOnSingleCandidate (types: javax.sql.DataSource; SearchStrategy: all) did not find a primary bean from beans 'remoteDataSource', 'localDataSource'

我也试过

@SpringBootApplication(exclude = {
            DataSourceAutoConfiguration.class, 
            DataSourceTransactionManagerAutoConfiguration.class})
    @EnableAutoConfiguration(exclude = {
            DataSourceAutoConfiguration.class, 
            DataSourceTransactionManagerAutoConfiguration.class})

然后我得到了

A component required a bean of type 'org.springframework.transaction.PlatformTransactionManager' that could not be found.

【问题讨论】:

    标签: spring spring-boot spring-data spring-jdbc jdbctemplate


    【解决方案1】:

    您可以使用 bean 名称来限定它们:

    @Bean(name = "localDataSource")
    public DataSource localDataSource() {
      ...
    }
    
    @Bean(name = "remoteDataSource")
    public DataSource remoteDataSource() {
      ...
    }
    

    请注意:您必须为您的 JdbcTemplate bean 做同样的事情 - 只需给它们一个名称,它就会起作用。 有关更多信息,请参阅 Spring JavaDoc:Bean

    @Bean(name = "localJdbcTemplate")
    public JdbcTemplate localJdbcTemplate() {
      return new JdbcTemplate(localDataSource());
    }
    

    当您通过自动装配 (@Autowired) 在导出服务实现中使用 JdbcTemplate bean 时,您需要使用 @Qualifier 来限定它们:

    @Autowired
    @Qualifier("localJdbcTemplate")
    private JdbcTemplate jdbcTemplate;
    
    @Autowired
    @Qualifier("remoteJdbcTemplate")
    private JdbcTemplate jdbcTemplate;
    

    【讨论】:

      【解决方案2】:

      Bean 从方法名称中获取名称,提供 name 属性只是使其显式(保持名称与方法名称相同)。关于@Bean(name="...")@Qualifier 的总体建议并没有为我解决错误。

      我使用两个嵌入式数据库设置示例项目,并得到与 aothor 相同的错误。 Spring 建议将其中一个 DataSource bean 注释为@Primary,事实上,这可以修复错误。通常,当一些其他应用程序部分只想查看一个或一个主 DataSource(如果存在多个)时,就会发生这种情况。

      似乎更好的解决方案是禁用不需要的自动配置 bean,保持其余代码不变:

      @SpringBootApplication(exclude = {
          DataSourceAutoConfiguration.class, 
          DataSourceTransactionManagerAutoConfiguration.class})
      

      或:

      @EnableAutoConfiguration(exclude = {
          DataSourceAutoConfiguration.class, 
          DataSourceTransactionManagerAutoConfiguration.class})
      

      取决于正在使用的注释。

      如果作者不使用任何 JPA 提供程序并直接使用 JdbcTemplate 操作,它可能是一个合适的解决方案。

      【讨论】:

      • 这就是我的解决方案。接受的答案对我不起作用。
      猜你喜欢
      • 2023-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-25
      • 2018-08-24
      • 2016-07-30
      • 2018-10-13
      • 2020-05-28
      相关资源
      最近更新 更多