原因:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有名为'entityManagerFactory'的bean可用

问题描述 投票:2回答:3

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

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

主数据库]

    @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

您知道如何解决此问题吗?

当我删除时:

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

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

java spring spring-boot jdbc spring-data-jpa
3个回答
0
投票

在您的数据源定义上添加注释@ConfigurationProperties("spring.datasource"),例如WarehouseDataSource()和productionDataSource()


0
投票

眼睛!我建议按照每个微服务模式跟踪数据库,并更改您的解决方案/体系结构,以使一个微服务具有一个生产微数据库,而一个微服务具有一个仓库微数据库!


-1
投票

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

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

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

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

并且仔细检查配置,请禁用除精确配置以外的任何其他类型的@EnableJpaRepositories@EntityScan

并且在创建LocalContainerEntityManagerFactoryBean时不要使用注入的EntityManagerFactoryBuilder:简单的new LocalContainerEntityManagerFactoryBean()会更好地工作。

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

© www.soinside.com 2019 - 2024. All rights reserved.