JPA 数据存储库 - 找到 2 个 EntityManager 类型的 bean

Posted

技术标签:

【中文标题】JPA 数据存储库 - 找到 2 个 EntityManager 类型的 bean【英文标题】:JPA Data Repository - 2 beans of type EntityManager found 【发布时间】:2020-03-19 16:45:38 【问题描述】:

我正在尝试在我的 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;
    


第二个Config类:


@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 data JPA Repo 定义如下

演示回购


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


Repo 的使用方式如下

@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

有人对如何解决这个问题有建议吗?我可以考虑为每个 repo 注入正确的 entitymanager,但是我不知道该怎么做。

提前致谢。在此处或其他网站上找不到任何解决方案。

【问题讨论】:

***.com/questions/59002892/…的可能重复 @Ramu Nope,已经在这里查看了答案,否则我不会问。 您可以尝试使用限定符注解明确指定 bean 名称,因为 spring 正在寻找两个 bean 并且不知道要注入哪个。 对不起。你的要求看起来和那个很相似。看看下面的对你有帮助吗? ***.com/questions/45663025/… 谢谢@SB 你有一个例子如何在 spring Config 类以及 repos 的 impl 类中正确实现限定符吗? 【参考方案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);
    


这就是您访问多个数据库所需的一切?

  注意:不要忘记和 请记住,这只是另一种选择,以多种方式存在?

希望你能理解,?

【讨论】:

在您的 application.properties 中,使用您的数据库凭据,在此示例中是假凭据

以上是关于JPA 数据存储库 - 找到 2 个 EntityManager 类型的 bean的主要内容,如果未能解决你的问题,请参考以下文章

如何使用spring JPA存储库保存@lob数据

Spring JPA 存储库接口和默认方法用例

如何使用 jpa 存储库查询多对一映射

存储库注释不适用于 Spring 数据 JPA

Spring-Data-Jpa 存储库 - 实体列名称上的下划线

如何在 Spring JPA 存储库中加入多个表的结果