本文介绍了原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有名为'entityManagerFactory'的bean可用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将Spring Boot配置为使用2个JNDI数据源.我尝试了这种配置:

I want to configure Spring Boot to use 2 JNDI datasources. I tried this configuration:

application.properties

spring.production.datasource.jndi-name=java:/global/production_gateway
spring.production.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.production.datasource.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.production.datasource.jpa.show-sql = true
spring.production.datasource.jpa.hibernate.ddl-auto = update

spring.warehouse.datasource.jndi-name=java:/global/production_warehouse
spring.warehouse.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.warehouse.datasource.jpa.properties.hibernate.dialect=org.hibernate.dialect.MariaDBDialect
spring.warehouse.datasource.jpa.show-sql = true
spring.warehouse.datasource.jpa.hibernate.ddl-auto = update

主数据库

primary database

    @Configuration
@EnableJpaRepositories(
        basePackages = "org.datalis.plugin.production.entity",
        entityManagerFactoryRef = "productionEntityManagerFactory",
        transactionManagerRef = "productionTransactionManager"
    )
@EnableTransactionManagement
public class ContextProductionDatasource {

    @Primary
    @Bean(name = "productionDataSourceProperties")
    @ConfigurationProperties(prefix="spring.production.datasource")
    public JndiPropertyHolder productionDataSourceProperties() {
        return new JndiPropertyHolder();
    }

    @Primary
    @Bean(name = "productionDataSource")
    @ConfigurationProperties(prefix="spring.production.datasource")
    public DataSource productionDataSource() {
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource(productionDataSourceProperties().getJndiName());
        return dataSource;
    }

    @Primary
    @Bean(name = "productionEntityManager")
    public EntityManager productionEntityManager(EntityManagerFactory emf) {
        return emf.createEntityManager();
    }

    @Primary
    @Bean(name = "productionEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean productionEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.hbm2ddl.auto", "update");
        return builder
                .dataSource(productionDataSource())
                .packages("org.datalis.plugin.production.entity")
                .persistenceUnit("production")
                .properties(properties)
                .build();
    }

    @Primary
    @Bean(name = "productionTransactionManager")
    public PlatformTransactionManager productionTransactionManager(final EntityManagerFactory emf) {
        final JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }

    @Primary
    @Bean(name = "productionExceptionTranslation")
    public PersistenceExceptionTranslationPostProcessor productionExceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    private static class JndiPropertyHolder {
        private String jndiName;

        public String getJndiName() {
            return jndiName;
        }

        public void setJndiName(String jndiName) {
            this.jndiName = jndiName;
        }
    }
}

第二个数据源:

    @Configuration
@EnableJpaRepositories(
        basePackages = "org.datalis.plugin.warehouse.entity",
        entityManagerFactoryRef = "warehouseEntityManagerFactory",
        transactionManagerRef = "warehouseTransactionManager"
    )
@EnableTransactionManagement
public class ContextWarehouseDatasource {

    @Bean(name = "warehouseDataSourceProperties")
    @ConfigurationProperties(prefix="spring.warehouse.datasource")
    public JndiPropertyHolder warehouseDataSourceProperties() {
        return new JndiPropertyHolder();
    }

    @Bean(name = "warehouseDataSource")
    @ConfigurationProperties(prefix="spring.warehouse.datasource")
    public DataSource warehouseDataSource() {
        JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
        DataSource dataSource = dataSourceLookup.getDataSource(warehouseDataSourceProperties().getJndiName());
        return dataSource;
    }

    @Bean(name = "warehouseEntityManager")
    public EntityManager warehouseEntityManager(EntityManagerFactory emf) {
        return emf.createEntityManager();
    }

    @Bean(name = "warehouseEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean warehouseEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.hbm2ddl.auto", "update");
        return builder
                .dataSource(warehouseDataSource())
                .packages("org.datalis.plugin.warehouse.entity")
                .persistenceUnit("warehouse")
                .properties(properties)
                .build();
    }

    @Bean(name = "warehouseTransactionManager")
    public PlatformTransactionManager warehouseTransactionManager(final EntityManagerFactory emf) {
        final JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);
        return transactionManager;
    }

    @Bean(name = "warehouseExceptionTranslation")
    public PersistenceExceptionTranslationPostProcessor warehouseExceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    private static class JndiPropertyHolder {
        private String jndiName;

        public String getJndiName() {
            return jndiName;
        }

        public void setJndiName(String jndiName) {
            this.jndiName = jndiName;
        }
    }
}

部署代码时出现异常:

    Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available

完整错误堆栈: https://pastebin.com/bBZPZGfu

您知道我该如何解决这个问题?

Do you know how I can solve this issue?

当我移除时:

@Primary
    @Bean(name = "productionEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean productionEntityManagerFactory(
            EntityManagerFactoryBuilder builder) {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put("hibernate.hbm2ddl.auto", "update");
        return builder
                .dataSource(productionDataSource())
                .packages("org.datalis.plugin.production.entity")
                .persistenceUnit("production")
                .properties(properties)
                .build();
    }

该软件包已正确部署.知道为什么吗?

The package is properly deployed. Any idea why?

推荐答案

主要问题是要有2个不同的实体管理器,它们可以访问不同的数据库.

The main problem is to have 2 different Entity managers, which access different databases.

因此是异常的原因:Spring Data JPA尝试创建一组存储库,但不知道要使用哪个实体管理器工厂.默认情况下,Spring Data JPA期望仅一个实体管理器工厂bean,最好命名为entityManagerFactory,但是您没有这样的实体.

So the cause of the exception: Spring Data JPA tries to create a set of repositories but does not know which entity manager factory to use. By default, Spring Data JPA expects only one Entity manager factory bean, preferably named entityManagerFactory, but you do not have such.

因此,您必须非常精确地进行配置:例如,您可以将代码组织为两个包:...warehouse.*app.production.*,然后可以指定Spring Data JPA的精确配置:@EnableJpaRepositories(basePackages = "...warehouse.**", entityManagerFactoryRef = "warehouseEntityManagerFactory")和生产@EnableJpaRepositories(basePackages = "...production.**", entityManagerFactoryRef = "productionEntityManagerFactory").

So you have to be really precise in configuration: for example, you can organize your code in 2 packages: ...warehouse.* and app.production.*, then you can specify a precise configuration of Spring Data JPA: @EnableJpaRepositories(basePackages = "...warehouse.**", entityManagerFactoryRef = "warehouseEntityManagerFactory") and for production @EnableJpaRepositories(basePackages = "...production.**", entityManagerFactoryRef = "productionEntityManagerFactory").

第二步是确保不执行默认的Data JPA实例化:添加配置属性spring.data.jpa.repositories.enabled=false将解决此问题.

The second step is to ensure that no default Data JPA instantiation is done: adding the configuration property spring.data.jpa.repositories.enabled=false will resolve this.

并仔细查看配置,请禁用除精确配置上定义的其他任何@EnableJpaRepositories@EntityScan.

And looking through the configuration disable any kind of other @EnableJpaRepositories or @EntityScan except defined above precise configurations.

并且在创建LocalContainerEntityManagerFactoryBean时不要使用注入的EntityManagerFactoryBuilder:死掉的简单new LocalContainerEntityManagerFactoryBean()会更好.

And during creation of LocalContainerEntityManagerFactoryBean do not use injected EntityManagerFactoryBuilder: dead simple new LocalContainerEntityManagerFactoryBean() will work better.

最后但并非最不重要的一点是,它通常与应用程序相关:您必须考虑两阶段提交事务:您有2个数据源,可以在单个事务中访问这些数据源,但是每个数据源都由不同的事务管理器管理.

And last but not least, related to application in general: you have to think about 2-phase commit transactions: you have 2 data sources, which can be accessed within single transactions but each of them is managed by different transaction managers.

这篇关于原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有名为'entityManagerFactory'的bean可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-29 16:50