【问题标题】:Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available引起:org.springframework.beans.factory.NoSuchBeanDefinitionException:没有名为“entityManagerFactory”的bean可用
【发布时间】:2020-03-19 06:19:32
【问题描述】:

我想将 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();
    }

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

【问题讨论】:

  • 错误告诉你什么地方出错了:Failed to load driver class org.mariadb.jdbc.Driver。您需要在类路径中有 mariadb 驱动程序 jar。修复你的依赖。
  • 请在问题中包含异常堆栈跟踪,不要依赖外部站点。
  • 寻找现有答案怎么样? stackoverflow.com/questions/24520602/…
  • @Tristan 我试试这个 - 请参阅上面的配置文件:@EnableJpaRepositories( basePackages = "org.datalis.plugin.production.entity", entityManagerFactoryRef = "productionEntityManagerFactory", transactionManagerRef = "productionTransactionManager" 但它不起作用。
  • 在主数据库中重命名方法参数:EntityManager productionEntityManager(EntityManagerFactory emf) by EntityManager productionEntityManager(EntityManagerFactory productionEntityManagerFactory) 对第二个执行相同操作:warehouseEntityManager(EntityManagerFactory emf) by warehouseEntityManager(EntityManagerFactory warehouseEntityManagerFactory)跨度>

标签: java spring spring-boot jdbc spring-data-jpa


【解决方案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 个数据源,可以在单个事务中访问它们,但每个都由不同的事务管理器管理。

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      哎呀!我建议遵循每个微服务模式的数据库,并将您的解决方案/架构更改为拥有一个带有生产微数据库的微服务,以及一个带有仓库微数据库的微服务!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-10-06
        • 2018-11-07
        • 1970-01-01
        • 2020-10-23
        • 2012-11-20
        • 2014-11-14
        • 2013-02-01
        • 1970-01-01
        相关资源
        最近更新 更多