Spring Boot JPA多个数据源错误

时间:2017-01-26 19:50:28

标签: spring hibernate jpa spring-boot spring-data

我想将我的春季启动应用程序连接到2个数据库。所以根据一个教程,我创建了2个配置类。

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


}

申请类

@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("*");
            }
        };
    }




}

当我尝试运行应用程序时,我收到以下错误。

***************************
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

我把@Primary放到第一个配置类(根据另一个教程)。当我在第一个配置类中执行该数据源时。问题是当我这样做时,第一个数据源也应用于所有jparepositories。

我是Spring的新手。我一直试图解决这个问题超过5个小时:(。提前感谢您提供的任何帮助。

完整日志

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

3 个答案:

答案 0 :(得分:4)

将其中一个bean标记为主要

    @Primary
    @Bean
    public EntityManagerFactory entityManagerFactory() {
}

答案 1 :(得分:2)

您的Spring Boot应用程序通过 @WebMvcAutoConfiguration 隐式激活Spring Web Mvc,这是通过在类路径中包含Servlet.class等来触发的。此 @WebMvcAutoConfiguration 需要类型为 EntityManagerFactory 的bean。但是,您已经注册了两个这样的bean adminEntityManagerFactory和sumLogEntityManagerFactory。因此,您必须在相应的 @Bean 方法之上通过 @Primary 告诉Spring Web Mvc哪个是您首选的。或者,如果您不需要Web Mvc自动配置,请通过 @EnableAutoConfiguration(exclude = {WebMvcAutoConfiguration})将其关闭并手动配置Web Mvc。

答案 2 :(得分:0)

找到了解决方案。您需要为配置类中的每个bean指定一个名称。

新配置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(name = "adminTransactionManager")
    PlatformTransactionManager adminTransactionManager() {
        return new JpaTransactionManager(adminEntityManagerFactory().getObject());
    }

    @Bean(name = "adminEntityManagerFactory")
    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(name = "adminDataSource")
    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;
    }


}

新配置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;


    @Primary
    @Bean(name = "sumLogTransactionManager")
    PlatformTransactionManager sumLogTransactionManager() {
        return new JpaTransactionManager(sumLogEntityManagerFactory().getObject());
    }



    @Primary
    @Bean(name = "sumLogEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean sumLogEntityManagerFactory() {


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

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();

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


    @Primary
    @Bean(name = "summaryLogDataSource")
    DataSource summaryLogDataSource() {

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


}

----------------------------------------------- -------------------------------------------------- -------------------------------

事实证明我为两个数据源bean使用了相同的方法名称。这就是为什么只有一个数据源用于所有jparepos的原因。感谢@ Javatar81解释bean命名如何工作