Home > Software design >  In Spring Boot (v2.6.6), how can I pull from two data sources and have them separately accessible?
In Spring Boot (v2.6.6), how can I pull from two data sources and have them separately accessible?

Time:08-06

I have two databases I need instances of at the same time, they are running on a oracle weblogic server rather than locally. In a configurator class, I have specified the sources and tested the connection and both DBs pull data properly. (When used one at a time, or with one as @Primary)

@Configuration
public class appDatabaseConfiguration {

 @Bean
 @Primary
 public DataSource dataSourceA() throws Exception{
     JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
     JndiTemplate corpdwJndiTemplate = new JndiTemplate();
     return dataSourceLookup.getDataSource("<DBAProperties>");
 }
 
 @Bean
 public DataSource dataSourceB() throws Exception{
     JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
     JndiTemplate jndiTemplate = new JndiTemplate();
     return dataSourceLookup.getDataSource("<DBBProperties>");
 }
}

However, I am unable to use @Qualifier to tell the instantiation which bean in the configuration to select-

@Service
public class DaoImpl implements Dao{
    @Autowired
    @Qualifier("dataSourceA")
    private JdbcTemplate dataSourceA;
    
    @Autowired
    @Qualifier("dataSourceB")
    private JdbcTemplate dataSourceB;
    
    public String getData() {

         resultsA = dataSourceA.queryForObject("SELECT COUNT(*) FROM TABLE", String.class);
                
         resultsB = dataSourceB.queryForObject("SELECT COUNT(*) FROM TABLE", String.class);     
        
         return resultsA   resultsB;
    }
}

When @Qualifier is not used: DataSourceA Query will succeed, but DataSourceB will fail (Table or View doesn't exist error)- because it is pulling the @Primary bean for both instantiations

When @Qualifier is used: Application errors with-

org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 
'org.springframework.jdbc.core.JdbcTemplate' available: expected at least 1 bean which 
qualifies as autowire candidate. Dependency annotations: 
{@org.springframework.beans.factory.annotation.Autowired(required=dataSourceA)} 

I have tried adding specific names to the bean like @Bean("dataSourceA"), @Bean(name="dataSourceB") rather than relying on the function name and several other syntax changes but no results. Does anyone have some insight here?

Note: Even when one datasource bean is commented out, and the other has only a name and not @primary it still throws the same autowire bean error, so I don't believe that the annotation is functioning properly in my project (or I'm using it wrong).

CodePudding user response:

You'll have to create two JdbcTemplates each configured with a different datasource and autowire with the qualifier of the template, for example with

@Bean
@Primary
public JdbcTemplate jdbcTemp1(@Qualifier("dataSourceA") DataSource ds) {
    return new JdbcTemplate(ds);
}

@Bean
public JdbcTemplate jdbcTemp2(@Qualifier("dataSourceB") DataSource ds) {
    return new JdbcTemplate(ds);
}

...

@Autowired
@Qualifier("jdbcTemp2")
private JdbcTemplate jdbcTemplate;

CodePudding user response:

It's because the type of your beans defined in the @Configuration is DataSource and in your @Service you inject beans of type JdbcTemplate.

To make it work, you should create two more beans of type JdbcTemplate using your two DataSource like this :

@Configuration
public class appDatabaseConfiguration {

 @Bean
 @Primary
 public DataSource dataSourceA() throws Exception{
     JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
     JndiTemplate corpdwJndiTemplate = new JndiTemplate();
     return dataSourceLookup.getDataSource("<DBAProperties>");
 }
 
 @Bean
 public DataSource dataSourceB() throws Exception{
     JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
     JndiTemplate jndiTemplate = new JndiTemplate();
     return dataSourceLookup.getDataSource("<DBBProperties>");
 }

 @Bean(name="jdbcTemplateA")
 public JdbcTemplate jdbcTemplateA() {
     return new JdbcTemplate(dataSourceA());
 }

 @Bean(name="jdbcTemplateB")
 public JdbcTemplate jdbcTemplateB() {
     return new JdbcTemplate(dataSourceB());
 }
}

And then, inject your beans using @Qualifier("jdbcTemplateA") or @Qualifier("jdbcTemplateB")

  • Related