Spring Boot Multiple Databse:没有类型为EntityManagerFactoryBuilder

时间:2018-09-19 08:05:01

标签: spring-boot spring-data-jpa

我们的Spring Boot应用程序中有两个数据库,分别称为source和target。这是这些的配置

源配置

package com.alex.myapp.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "sourceManagerFactory",
        transactionManagerRef = "sourceTransactionManager",
        basePackages = {"com.alex.myapp.source.repository"}
)
public class SourceDbConfiguration {

    @Autowired
    private Environment env;

    @Primary
    @Bean(name = "sourceManagerFactory")
    public LocalContainerEntityManagerFactoryBean
    sourceManagerFactory(EntityManagerFactoryBuilder builder) {
        LocalContainerEntityManagerFactoryBean em = builder
                .dataSource(sourceDataSource())
                .packages("com.alex.myapp.source.entity")
                .persistenceUnit("source")
                .build();
        return em;
    }

    @Primary
    @Bean
    public DataSource sourceDataSource() {
        DriverManagerDataSource dataSource
                = new DriverManagerDataSource();
        dataSource.setDriverClassName(
                env.getProperty("spring.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("spring.datasource.url"));
        dataSource.setUsername(env.getProperty("spring.datasource.username"));
        dataSource.setPassword(env.getProperty("spring.datasource.password"));

        return dataSource;
    }

    @Primary
    @Bean(name = "sourceTransactionManager")
    public PlatformTransactionManager sourceTransactionManager(
            @Qualifier("sourceManagerFactory") EntityManagerFactory
                    sourceManagerFactory
    ) {
        return new JpaTransactionManager(sourceManagerFactory);
    }
}

目标配置

package com.alex.myapp.config;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        entityManagerFactoryRef = "targetManagerFactory",
        transactionManagerRef = "targetTransactionManager",
        basePackages = {"com.alex.myapp.target.repository"}
)
public class TargetDbConfiguration {

    @Autowired
    private Environment env;

    @Primary
    @Bean(name = "targetManagerFactory")
    public LocalContainerEntityManagerFactoryBean
    targetManagerFactory(EntityManagerFactoryBuilder builder) {
        LocalContainerEntityManagerFactoryBean em = builder
                .dataSource(targetDataSource())
                .packages("com.alex.myapp.target.entity")
                .persistenceUnit("target")
                .build();
        return em;
    }

    @Primary
    @Bean
    public DataSource targetDataSource() {
        DriverManagerDataSource dataSource
                = new DriverManagerDataSource();
        dataSource.setDriverClassName(
                env.getProperty("target.datasource.driver-class-name"));
        dataSource.setUrl(env.getProperty("target.datasource.url"));
        dataSource.setUsername(env.getProperty("target.datasource.username"));
        dataSource.setPassword(env.getProperty("target.datasource.password"));

        return dataSource;
    }

    @Bean(name = "targetTransactionManager")
    public PlatformTransactionManager targetTransactionManager(
            @Qualifier("targetManagerFactory") EntityManagerFactory
                    targetManagerFactory) {
        return new JpaTransactionManager(targetManagerFactory);
    }
}

当我尝试启动服务器时,它抛出以下提到的错误

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2018-09-19 13:30:53 - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'sourceManagerFactory' defined in class path resource [com/alex/myapp/config/SourceDbConfiguration.class]: Unsatisfied dependency expressed through method 'sourceManagerFactory' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:732)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:474)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1247)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1096)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:535)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1089)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:859)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)

如果我注释掉目标配置的类级别注释,一切正常。似乎两个数据库配置都相互冲突。

2 个答案:

答案 0 :(得分:4)

@Primary必须在所需类型中的一个bean上完全使用。

@Primary javadoc提取

  

指示当有多个候选者有资格自动装配单值依赖项时,应优先考虑Bean。如果候选对象中仅存在一个“主” bean,它将是自动装配的值。

答案 1 :(得分:1)

You have an error in your code. You specify

@Primary 

Annotation for both of datasources, therefore Spring claims. So you need to remove this annotation from one of your class and all will be ok.

Also please note that Primary annotation is helpful whenever we’re going to implicitly or explicitly inject the transaction manager without specifying which one by name.