Репозиторий данных JPA — найдено 2 bean-компонента типа EntityManager

Я пытаюсь настроить второй источник данных в своем приложении Spring. Ниже приведены 2 класса конфигурации для 2 источников данных:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.XYXYale.persistence.XY",
        entityManagerFactoryRef = "awEntityManagerFactory",
        transactionManagerRef= "awTransactionManager"
)
public class Datasource1DataSourceConfig {

    @Value("${spring.first-datasource.url}")
    private String url;

    @Value("${spring.first-datasource.username}")
    private String username;

    @Value("${spring.first-datasource.password}")
    private String pw;

    @Value("${spring.first-datasource.driver-class-name}")
    private String driver;


    @Bean
    @Primary
    @ConfigurationProperties("spring.first-datasource")
    public DataSourceProperties awDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @Primary
    @Qualifier("awEntityManagerFactory")
    public DataSource awDataSource() {

        DriverManagerDataSource dataSource
                = new DriverManagerDataSource();
        dataSource.setDriverClassName(
                driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(pw);

        return dataSource;
    }

    @Primary
    @Bean(name = "awEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean awEntityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(awDataSource());
        em.setPersistenceUnitName("XY");



");
        em.setPackagesToScan(new String[] { "com.XY.XY.domain.XY" });
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
        em.setJpaVendorAdapter(vendorAdapter);
        return em;
    }

    @Primary
    @Bean
    public PlatformTransactionManager awTransactionManager() {
        JpaTransactionManager transactionManager
                = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(
                awEntityManagerFactory().getObject());
        return transactionManager;
    }

}

Второй класс конфигурации:


@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.XYXYale.persistence.YX",
        entityManagerFactoryRef = "sndEntityManagerFactory",
        transactionManagerRef= "sndTransactionManager"
)
public class SndDataSourceConfig {

    @Value("${spring.second-datasource.jdbcUrl}")
    private String url;

    @Value("${spring.second-datasource.username}")
    private String username;

    @Value("${spring.second-datasource.password}")
    private String pw;

    @Value("${spring.second-datasource.driver-class-name}")
    private String driver;

    @Bean
    @ConfigurationProperties("spring.second-datasource")
    public DataSourceProperties sndDataSourceProperties() {
        return new DataSourceProperties();
    }

    @Bean
    @Qualifier("sndEntityManagerFactory")
    public DataSource sndDataSource() {
        DriverManagerDataSource dataSource
                = new DriverManagerDataSource();
        dataSource.setDriverClassName(
                driver);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(pw);

        return dataSource;
    }

    @Bean(name = "sndEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean sndEntityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(sndDataSource());
        em.setPersistenceUnitName("snd");
        em.setPackagesToScan(new String[] { "com.XY.XY.domain.YX" });
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
        em.setJpaVendorAdapter(vendorAdapter);
        return em;
    }

    @Bean
    public PlatformTransactionManager sndTransactionManager() {
        JpaTransactionManager transactionManager
                = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(
                sndEntityManagerFactory().getObject());
        return transactionManager;
    }

}

У меня есть в com.XYXYale.persistence.XY репозиторий Spring данных JPA, определенный следующим образом

Демо-репозиторий


@Repository
public interface DemoRepo extends CrudRepository<Demo, String>, DemoRepoCustom{
}

ДемоРепоПользовательский

@NoRepositoryBean
public interface DemoRepoCustom {
    Demo returnDemoContent();
}

DemoRepoImpl

public class DemoRepoImpl extends QuerydslRepositorySupport implements DemoRepoCustom {

    public DemoRepoImpl() {
        super(Demo.class);
    }

    public Demo returnDemoContent(){
        return something;
    }

}

Репо используется следующим образом

@Autowired
DemoRepo demoRepo;

Я получаю это исключение:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoRepositoryImpl': Unsatisfied dependency expressed through method 'setEntityManager' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected single matching bean but found 2: org.springframework.orm.jpa.SharedEntityManagerCreator#0,org.springframework.orm.jpa.SharedEntityManagerCreator#1
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:678)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:90)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:376)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1411)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:307)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1255)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1175)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:595)
    ... 55 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManager' available: expected single matching bean but found 2: org.springframework.orm.jpa.SharedEntityManagerCreator#0,org.springframework.orm.jpa.SharedEntityManagerCreator#1
    at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:221)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1233)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1175)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:670)
    ... 70 more

У кого-нибудь есть предложение о том, как это решить? Я мог бы подумать о том, чтобы ввести правильный менеджер сущностей в каждое репо, однако я понятия не имею, как это сделать.

Заранее спасибо. Не могу найти решение ни здесь, ни на других сайтах.


person GreeceTom    schedule 24.11.2019    source источник
comment
Возможный дубликат stackoverflow.com/questions/59002892/   -  person Ramu    schedule 24.11.2019
comment
@Ramu Нет, я уже просмотрел ответы здесь, иначе я бы не спрашивал.   -  person GreeceTom    schedule 24.11.2019
comment
Вы можете попробовать использовать аннотацию квалификатора, чтобы явно указать имя компонента, поскольку Spring находит два компонента и не знает, какой из них вводить.   -  person S B    schedule 24.11.2019
comment
Прошу прещения за это. Ваше требование было очень похоже на это. Посмотрите, поможет ли вам следующее? stackoverflow.com/questions/45663025/   -  person Ramu    schedule 24.11.2019
comment
Спасибо @SB У вас есть пример того, как квалификатор правильно реализован в классах Spring Config, а также в классах impl репозиториев?   -  person GreeceTom    schedule 24.11.2019
comment
@GreeceTom - посмотрите, поможет ли это - stackoverflow.com/questions/49127000/   -  person S B    schedule 24.11.2019
comment
Что за entityManagerFactoryRef на втором? Здесь будет полезен полный пример.   -  person Andy Wilkinson    schedule 24.11.2019
comment
@SB Спасибо, но на самом деле это не показывает, как вставлять его в репозитории.   -  person GreeceTom    schedule 24.11.2019
comment
GreeceTom - при маркировке классов/методов репозитория с помощью @Transactional вы можете указать менеджера транзакций, например. @Transactional(awTransactionManager)   -  person S B    schedule 24.11.2019
comment
@SB Спасибо за предложение, но все еще получаю ту же ошибку.   -  person GreeceTom    schedule 24.11.2019
comment
@AndyWilkinson Только что добавил другой класс конфигурации.   -  person GreeceTom    schedule 24.11.2019
comment
@GreeceTom - посмотрите пример по этой ссылке - baeldung.com/spring-data -jpa-несколько баз данных   -  person S B    schedule 25.11.2019
comment
@SB Это то, что я сделал, но это не то, почему я разместил этот вопрос здесь ...   -  person GreeceTom    schedule 25.11.2019
comment
@GreeceTom, не уверен, устранена ли ваша ошибка сейчас, но приведенная выше конфигурация немного отличается от приведенной в ссылке. Bean и Primary не нуждаются в Qualifier во время объявления.   -  person S B    schedule 28.11.2019


Ответы (1)


если вам нужно будет подключиться к более чем одному источнику данных.
и предполагая, что у вас уже есть приложение Spring, используйте этот код ????:
в вашем application.properties добавьте этот код:

# DEFAULT CONFIG
spring.main.banner-mode=off
server.port=2020
# CUSTOM PREFIX FOR SQL SERVER
sqlserver.datasource.driverClassName=com.microsoft.sqlserver.jdbc.SQLServerDriver
sqlserver.datasource.jdbcUrl=jdbc:sqlserver://192.168.9.44;databaseName=myAwesomeDB
sqlserver.datasource.username=someUser
sqlserver.datasource.password=somePass
# DEFAULT PREFIX FOR POSTGRES
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://192.168.6.125:5432/wilmer
spring.datasource.username=admWinter
spring.datasource.password=wilmer43nlp

теперь создайте класс с именем DataSourceDBConfig.java и добавьте следующий код:

package com.example.demo.config;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
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.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import javax.sql.DataSource;

/**
 * @author Wilmer Villca
 * @version 0.0.1
 */

@Configuration
public class DataSourceDBConfig {

    private final Environment env;

    @Autowired
    public DataSourceDBConfig(Environment env) {
        this.env = env;
    }

    @Bean
    @Primary
    @ConfigurationProperties(prefix = "sqlserver.datasource")
    public DataSource dataSourceFromSqlServer() {
        return DataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public HikariDataSource dataSourceFromPostgres() {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setDriverClassName("org.postgresql.Driver");
        hikariConfig.setJdbcUrl(env.getProperty("spring.datasource.url"));
        hikariConfig.setUsername(env.getProperty("spring.datasource.username"));
        hikariConfig.setPassword(env.getProperty("spring.datasource.password"));
        return new HikariDataSource(hikariConfig);
    }

    @Bean
    @Qualifier("jdbcTemplateSqlServer")
    public JdbcTemplate jdbcTemplateSqlServer(@Qualifier("dataSourceFromSqlServer") DataSource ds) {
        return new JdbcTemplate(ds);
    }

    @Bean
    @Qualifier("jdbcTemplatePostgres")
    public JdbcTemplate jdbcTemplatePostgres(@Qualifier("dataSourceFromPostgres") DataSource ds) {
        return new JdbcTemplate(ds);
    }

}

это все, что вам нужно для доступа к нескольким базам данных ????

ПРИМЕЧАНИЕ: не забывайте и помните, что это только альтернатива, существует множество других способов ????

надеюсь ты понял ????

person Wilmer Villca    schedule 30.11.2019
comment
в вашем application.properties используйте свои учетные данные для базы данных, в этом примере это поддельные учетные данные - person Wilmer Villca; 30.11.2019