简体   繁体   中英

JPA Data Repository - 2 beans of type EntityManager found

I am trying to set up a second data source in my Spring application. Below are the 2 configuration classes for the 2 data sources:

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

}

The second Config class:


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

}

I have in com.XYXYale.persistence.XY a Spring data JPA Repo defined as follows

DemoRepo


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

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

}

The Repo is used in the following way

@Autowired
DemoRepo demoRepo;

I am getting this exception:

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

Anyone having a suggestion on how to solve that? I could think of injecting the correct entitymanager to each repo, however I have no idea how to do that.

Thanks in advance. Cant find any solution on here or other sites.

if you will need to connect to more than one data source.
and assuming that you have already your spring app, then use this code 👇:
in your application.properties add this code:

# 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

now create a class called DataSourceDBConfig.java and add this code:

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

}

that is all you need to to access multiple databases 😉

NOTE : Do not forget and remember that this only is an alternative, exist anothers many ways 🎉

i hope you understand, 👀

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM