8

I wanted to connect my spring boot app to 2 databases . So according to a tutorial i created 2 config classes.

Config Class 1

@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:database-configs.properties" })
@EnableJpaRepositories(
        basePackages = {"com.dialog.pod.ideabiz_admin.data_access_objects"},
        entityManagerFactoryRef = "adminEntityManagerFactory",
        transactionManagerRef = "adminTransactionManager")
public class IdeabizAdminConfig {


    @Autowired
    private Environment env;


    @Bean
    PlatformTransactionManager adminTransactionManager() {
        return new JpaTransactionManager(adminEntityManagerFactory().getObject());
    }

    @Bean
    LocalContainerEntityManagerFactoryBean adminEntityManagerFactory() {

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
       // jpaVendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

        factoryBean.setDataSource(adminDataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan("com.dialog.pod.ideabiz_admin.models");
        factoryBean.setJpaPropertyMap(jpaProperties());
        factoryBean.setPersistenceUnitName("adminDataSource");
        return factoryBean;
    }

    @Bean
    DataSource adminDataSource() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("admin.jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("admin.jdbc.url"));
        dataSource.setUsername(env.getProperty("admin.jdbc.username"));
        dataSource.setPassword(env.getProperty("admin.jdbc.password"));

        return dataSource;
    }


    private Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.implicit_naming_strategy","org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl");
        props.put("hibernate.physical_naming_strategy","com.dialog.pod.PhysicalNamingStrategyImpl");
        return props;
    }


}

Config Class 2

@Configuration
@EnableTransactionManagement
@PropertySource({ "classpath:database-configs.properties" })
@EnableJpaRepositories(
        basePackages = {"com.dialog.pod.ideabiz_log_summary.data_access_objects"},
        entityManagerFactoryRef = "sumLogEntityManagerFactory",
        transactionManagerRef = "sumLogTransactionManager")
public class IdeabizLogSummaryConfig {


    @Autowired
    private Environment env;


    @Bean
    PlatformTransactionManager sumLogTransactionManager() {
        return new JpaTransactionManager(sumLogEntityManagerFactory().getObject());
    }



    @Bean
    LocalContainerEntityManagerFactoryBean sumLogEntityManagerFactory() {


        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
       // jpaVendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

        factoryBean.setDataSource(adminDataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan("com.dialog.pod.ideabiz_log_summary.models");
        factoryBean.setJpaPropertyMap(jpaProperties());
        factoryBean.setPersistenceUnitName("sumLogDataSource");
        return factoryBean;
    }



    @Bean
    DataSource adminDataSource() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(env.getProperty("sumlog.jdbc.driverClassName"));
        dataSource.setUrl(env.getProperty("sumlog.jdbc.url"));
        dataSource.setUsername(env.getProperty("sumlog.jdbc.username"));
        dataSource.setPassword(env.getProperty("sumlog.jdbc.password"));

        return dataSource;
    }

    private Map<String, Object> jpaProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("hibernate.implicit_naming_strategy","org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl");
        props.put("hibernate.physical_naming_strategy","com.dialog.pod.PhysicalNamingStrategyImpl");
        return props;
    }


}

Application Class

@SpringBootApplication
@EnableAutoConfiguration (exclude = {  DataSourceAutoConfiguration.class })
@Configuration
@ComponentScan
public class PodApiApplication {

    public static void main(String[] args) {
        SpringApplication.run(PodApiApplication.class, args);
    }

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurerAdapter() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/").allowedOrigins("*");
            }
        };
    }




}

When i try to run the app i get following error.

***************************
APPLICATION FAILED TO START
***************************

Description:

Method requestMappingHandlerMapping in org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration required a single bean, but 2 were found:
    - adminEntityManagerFactory: defined by method 'adminEntityManagerFactory' in class path resource [com/dialog/pod/ideabiz_admin/IdeabizAdminConfig.class]
    - sumLogEntityManagerFactory: defined by method 'sumLogEntityManagerFactory' in class path resource [com/dialog/pod/ideabiz_log_summary/IdeabizLogSummaryConfig.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed


Process finished with exit code 1

I put @Primary to the first config class(according to another tutorial). When i do that datasource in the first config class works. Problem is when i do this first datasource also applied to all the jparepositories.

I'm new to Spring boot. I have been trying to solve this problem for over 5 hours :( . Thanks in advance for any help you are able to provide.

Full Log

2017-01-27 00:52:39.713  INFO 6704 --- [           main] com.dialog.pod.PodApiApplication         : Starting PodApiApplication on DESKTOP-4B89ITN with PID 6704 (started by y2ksh in H:\Spring MVC Workspace\platform-overview-dashboard\PODApi)
2017-01-27 00:52:39.718  INFO 6704 --- [           main] com.dialog.pod.PodApiApplication         : No active profile set, falling back to default profiles: default
2017-01-27 00:52:39.938  INFO 6704 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6e171cd7: startup date [Fri Jan 27 00:52:39 IST 2017]; root of context hierarchy
2017-01-27 00:52:41.712  INFO 6704 --- [           main] o.s.b.f.s.DefaultListableBeanFactory     : Overriding bean definition for bean 'adminDataSource' with a different definition: replacing [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=ideabizAdminConfig; factoryMethodName=adminDataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/dialog/pod/ideabiz_admin/IdeabizAdminConfig.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=ideabizLogSummaryConfig; factoryMethodName=adminDataSource; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/dialog/pod/ideabiz_log_summary/IdeabizLogSummaryConfig.class]]
2017-01-27 00:52:42.804  INFO 6704 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration' of type [class org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration$$EnhancerBySpringCGLIB$$3cc0fc3] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
2017-01-27 00:52:43.594  INFO 6704 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8081 (http)
2017-01-27 00:52:43.609  INFO 6704 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2017-01-27 00:52:43.609  INFO 6704 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.6
2017-01-27 00:52:43.810  INFO 6704 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2017-01-27 00:52:43.810  INFO 6704 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3891 ms
2017-01-27 00:52:44.247  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'dispatcherServlet' to [/]
2017-01-27 00:52:44.253  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'metricFilter' to: [/*]
2017-01-27 00:52:44.254  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2017-01-27 00:52:44.254  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2017-01-27 00:52:44.254  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2017-01-27 00:52:44.254  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2017-01-27 00:52:44.255  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'webRequestLoggingFilter' to: [/*]
2017-01-27 00:52:44.255  INFO 6704 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'applicationContextIdFilter' to: [/*]
2017-01-27 00:52:44.367  INFO 6704 --- [           main] o.s.j.d.DriverManagerDataSource          : Loaded JDBC driver: com.mysql.jdbc.Driver
2017-01-27 00:52:44.403  INFO 6704 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'adminDataSource'
2017-01-27 00:52:44.435  INFO 6704 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: adminDataSource
    ...]
2017-01-27 00:52:44.634  INFO 6704 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.11.Final}
2017-01-27 00:52:44.636  INFO 6704 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2017-01-27 00:52:44.641  INFO 6704 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2017-01-27 00:52:44.725  INFO 6704 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2017-01-27 00:52:45.302  INFO 6704 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2017-01-27 00:52:46.178  INFO 6704 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'adminDataSource'
2017-01-27 00:52:46.189  INFO 6704 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'sumLogDataSource'
2017-01-27 00:52:46.190  INFO 6704 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
    name: sumLogDataSource
    ...]
2017-01-27 00:52:46.228  INFO 6704 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQL5Dialect
2017-01-27 00:52:46.291  INFO 6704 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'sumLogDataSource'
2017-01-27 00:52:46.695  INFO 6704 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
2017-01-27 00:52:46.947  INFO 6704 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
2017-01-27 00:52:47.496  INFO 6704 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6e171cd7: startup date [Fri Jan 27 00:52:39 IST 2017]; root of context hierarchy
2017-01-27 00:52:47.560  WARN 6704 --- [           main] ationConfigEmbeddedWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping]: Factory method 'requestMappingHandlerMapping' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'openEntityManagerInViewInterceptor' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration$JpaWebConfiguration$JpaWebMvcConfiguration.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: expected single matching bean but found 2: adminEntityManagerFactory,sumLogEntityManagerFactory
2017-01-27 00:52:47.562  INFO 6704 --- [           main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'sumLogDataSource'
2017-01-27 00:52:47.563  INFO 6704 --- [           main] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'adminDataSource'
2017-01-27 00:52:47.566  INFO 6704 --- [           main] o.apache.catalina.core.StandardService   : Stopping service Tomcat
2017-01-27 00:52:47.586  INFO 6704 --- [           main] utoConfigurationReportLoggingInitializer : 

Error starting ApplicationContext. To display the auto-configuration report re-run your application with 'debug' enabled.
2017-01-27 00:52:47.592 ERROR 6704 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Method requestMappingHandlerMapping in org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration required a single bean, but 2 were found:
    - adminEntityManagerFactory: defined by method 'adminEntityManagerFactory' in class path resource [com/dialog/pod/ideabiz_admin/IdeabizAdminConfig.class]
    - sumLogEntityManagerFactory: defined by method 'sumLogEntityManagerFactory' in class path resource [com/dialog/pod/ideabiz_log_summary/IdeabizLogSummaryConfig.class]


Action:

Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed


Process finished with exit code 1
4
  • Can you update your question with the version of the code that contains the @Primary annotations? (You will need to use that.) Commented Jan 26, 2017 at 20:05
  • @gyoder do you mean spring boot version? 1.4 Commented Jan 26, 2017 at 20:09
  • no, the configuration class with the @Primary attribute(s) which then cause the same datasource to be applied to all repos Commented Jan 26, 2017 at 20:11
  • @gyoder config class 1 Commented Jan 26, 2017 at 20:14

3 Answers 3

7

Mark one of the beans as primary

    @Primary
    @Bean
    public EntityManagerFactory entityManagerFactory() {
}
Sign up to request clarification or add additional context in comments.

1 Comment

This is not a great solution because it assumes that one of the data sources can semantically be deemed "primary".
7

Your Spring Boot application implicitly activates Spring Web Mvc via WebMvcAutoConfiguration which is triggered by having, among others, Servlet.class in your class path. This WebMvcAutoConfiguration requires a bean of type EntityManagerFactory. However, you have registered two such beans adminEntityManagerFactory and sumLogEntityManagerFactory. So you have to tell Spring Web Mvc which is your preferred one via @Primary on top of the respective @Bean method. Alternatively if you don't need Web Mvc autoconfiguration switch it off by @EnableAutoConfiguration(exclude={WebMvcAutoConfiguration}) and configure Web Mvc manually.

2 Comments

Your explanation is great, could be better if it's nicely formatted.
@jumping_monkey I edited the response for formatting
1

It turns out i used same method name for both datasource beans . This was the reason why only one data source used for all jparepos. Thanks @Javatar81 for explaining how bean naming works

1 Comment

Name should not make a difference because the default name of a bean is given by the method's name. This time you've used @Primary correctly and this is why it works. Could you please check whether it still works without name attribute defined?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.