【问题标题】:Spring jpa - can't use more than one EntityManagerFactorySpring jpa - 不能使用多个 EntityManagerFactory
【发布时间】:2015-10-02 19:44:32
【问题描述】:

我正在开发一个使用 hibernate 和 jpa 作为持久层的 java spring mvc 应用程序。我有 2 个数据库,我想在 database1 中映射一些实体表,在 database2 中映射一些实体表。所以我定义了两个这样的配置类:

第一:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(value = "com.mycompany.project.persistence.orm.module.common",entityManagerFactoryRef = "commonEntityManagerFactory",transactionManagerRef = "commonTransactionManager")
public class PersistenceConfigCommon {

    public PersistenceConfigCommon() {
    }


    Properties additionalProperties() {
        return new Properties() {
            {  
                setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                setProperty("hibernate.hbm2ddl.auto", "update");
                setProperty("hibernate.show_sql", "true");
                setProperty("hibernate.enable_lazy_load_no_trans", "true");
                setProperty("hibernate.connection.CharSet", "utf8");
                setProperty("hibernate.connection.characterEncoding", "utf8");
                setProperty("hibernate.connection.useUnicode", "true");
            }
        };
    }

    @Primary
    @Bean(name = "commonEntityManagerFactory")
    public EntityManagerFactory commonEntityManagerFactory() {entityManagerFactoryBean");
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setPersistenceUnitName("common");
        factory.setDataSource(commonDataSource());
        factory.setPackagesToScan("com.mycompany.project.persistence.orm.module");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(Boolean.TRUE);
        vendorAdapter.setShowSql(Boolean.TRUE);
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setJpaProperties(additionalProperties());

        factory.afterPropertiesSet();
        return factory.getObject();
    }


    @Primary
    @Bean(name = "commonDataSource")
    public DataSource commonDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://10.10.1.11:3306/database1?characterEncoding=UTF-8");
        dataSource.setUsername("fpuser");
        dataSource.setPassword("fpdb$123456");

        return dataSource;
    }

    @Primary
    @Bean(name = "commonTransactionManager")
    public PlatformTransactionManager commonTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
           transactionManager.setEntityManagerFactory(commonEntityManagerFactory());
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

}

第二:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(value = "com.mycompany.project.persistence.orm.module.profile",entityManagerFactoryRef = "profileEntityManagerFactory",transactionManagerRef = "profileTransactionManager")
public class PersistenceConfigProfile {

    public PersistenceConfigProfile() {
    }


    Properties additionalProperties() {
        return new Properties() {
            {  
                setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                setProperty("hibernate.hbm2ddl.auto", "update");
                setProperty("hibernate.show_sql", "true");
                setProperty("hibernate.enable_lazy_load_no_trans", "true");
                setProperty("hibernate.connection.CharSet", "utf8");
                setProperty("hibernate.connection.characterEncoding", "utf8");
                setProperty("hibernate.connection.useUnicode", "true");
            }
        };
     }

    @Primary
    @Bean(name = "profileEntityManagerFactory")
    public EntityManagerFactory profileEntityManagerFactory() {entityManagerFactoryBean");
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setPersistenceUnitName("profile");
        factory.setDataSource(profileDataSource());
        factory.setPackagesToScan("com.mycompany.project.persistence.orm.module");

        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(Boolean.TRUE);
        vendorAdapter.setShowSql(Boolean.TRUE);
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setJpaProperties(additionalProperties());

        factory.afterPropertiesSet();
        return factory.getObject();
    }


    @Primary
    @Bean(name = "profileDataSource")
    public DataSource profileDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://10.10.1.63:3306/database2?characterEncoding=UTF-8");
        dataSource.setUsername("fpuser");
        dataSource.setPassword("fpdb$123456");

        return dataSource;
    }

    @Primary
    @Bean(name = "profileTransactionManager")
    public PlatformTransactionManager commonTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
           transactionManager.setEntityManagerFactory(commonEntityManagerFactory());
        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

}

请注意,这两个文件中的所有内容都相似,只是 common 已在第二个文件中转换为 profile 并且数据库名称和 ip 已更改。在 DAO 中我也写了这个:

@PersistenceContext(unitName = "common") //or "profile"
protected EntityManager entityManager;

@Override
public EntityManager getEntityManager() {
    return entityManager;
}

现在,当我运行项目时,出现以下异常:

 org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.persistence.EntityManagerFactory] is defined: expected single matching bean but found 2: commonEntityManagerFactory,profileEntityManagerFactory

我已经在这个异常中停留了 2 天。谁能帮我解决这个问题。感谢您的宝贵时间。

【问题讨论】:

    标签: java hibernate spring-mvc jpa entitymanager


    【解决方案1】:

    不确定它是否对您有帮助,但尝试将 commonEntityManagerFactory()profileEntityManagerFactory() 的返回值从 EntityManagerFactory 更改为 LocalContainerEntityManagerFactoryBean 并返回这些工厂实例而不是 factory.getObject()。这是我在当前项目中拥有的东西,并且效果很好。

    另一个猜测:您使用哪个 Spring Framework 版本?问题是最近在 Spring Framework 中出现了与您的问题相关的回归。以herehere 为例。回归在 4.1.4 中。如果您确定您的配置没问题,请尝试使用不同的 Spring 版本。希望这会有所帮助

    【讨论】:

    • 我测试了你的建议,但仍然是同样的例外:(
    • @hamed 我用另一个猜测更新了我的答案,希望对您有所帮助。
    • 我正在使用 spring 4.0.1.. 也许升级到 4.1.1 可以解决我的问题?
    • 我不确定,你应该试试看。如果您编辑您的问题并添加更多关于您的配置的信息(例如,您的存储库是如何注释的,您尝试从哪里访问EntityManager,相关的persistence.xml(如果有),应用程序上下文xmls(如果有))也会很好也许缺少部分信息可以帮助社区解决您的问题。
    【解决方案2】:

    由于是 Spring-Jpa 配置,你可能需要这样做:

    第一:

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(value = "com.mycompany.project.persistence.orm.module.common",entityManagerFactoryRef = "commonEntityManagerFactory",transactionManagerRef = "commonTransactionManager")
    public class PersistenceConfigCommon {
    
        public PersistenceConfigCommon() {
        }
    
    Properties additionalProperties() {
        return new Properties() {
            {  
                setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                setProperty("hibernate.hbm2ddl.auto", "update");
                setProperty("hibernate.show_sql", "true");
                setProperty("hibernate.enable_lazy_load_no_trans", "true");
                setProperty("hibernate.connection.CharSet", "utf8");
                setProperty("hibernate.connection.characterEncoding", "utf8");
                setProperty("hibernate.connection.useUnicode", "true");
            }
        };
    }
    
    @Primary
    @Bean(name = "commonEntityManagerFactory")
    @Qualifier(value="commonEntityManager")
    public EntityManagerFactory commonEntityManagerFactory() {entityManagerFactoryBean");
        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(commonDataSource());
        factory.setPackagesToScan("com.mycompany.project.persistence.orm.module");
    
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setGenerateDdl(Boolean.TRUE);
        vendorAdapter.setShowSql(Boolean.TRUE);
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setJpaProperties(additionalProperties());
    
        factory.afterPropertiesSet();
        return factory.getObject();
    }
    
    
    @Primary
    @Bean(name = "commonDataSource")
    public DataSource commonDataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://10.10.1.11:3306/database1?characterEncoding=UTF-8");
        dataSource.setUsername("fpuser");
        dataSource.setPassword("fpdb$123456");
    
        return dataSource;
    }
    
    @Primary
    @Bean(name = "commonTransactionManager")
    public PlatformTransactionManager commonTransactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
           transactionManager.setEntityManagerFactory(commonEntityManagerFactory());
        return transactionManager;
    }
    
    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }
    }
    

    第二:

    @Configuration
    @EnableTransactionManagement
    @EnableJpaRepositories(value = "com.mycompany.project.persistence.orm.module.profile",entityManagerFactoryRef = "profileEntityManagerFactory",transactionManagerRef = "profileTransactionManager")
    public class PersistenceConfigProfile {
    
        public PersistenceConfigProfile() {
        }
    
    
        Properties additionalProperties() {
            return new Properties() {
                {  
                    setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
                    setProperty("hibernate.hbm2ddl.auto", "update");
                    setProperty("hibernate.show_sql", "true");
                    setProperty("hibernate.enable_lazy_load_no_trans", "true");
                    setProperty("hibernate.connection.CharSet", "utf8");
                    setProperty("hibernate.connection.characterEncoding", "utf8");
                    setProperty("hibernate.connection.useUnicode", "true");
                }
            };
         }
    
        @Primary
        @Bean(name = "profileEntityManagerFactory")
        @Qualifier(value="profileEntityManager")
        public EntityManagerFactory profileEntityManagerFactory() {entityManagerFactoryBean");
            LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
            factory.setDataSource(profileDataSource());
            factory.setPackagesToScan("com.mycompany.project.persistence.orm.module");
    
            HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
            vendorAdapter.setGenerateDdl(Boolean.TRUE);
            vendorAdapter.setShowSql(Boolean.TRUE);
            factory.setJpaVendorAdapter(vendorAdapter);
            factory.setJpaProperties(additionalProperties());
    
            factory.afterPropertiesSet();
            return factory.getObject();
        }
    
    
        @Primary
        @Bean(name = "profileDataSource")
        public DataSource profileDataSource() {
            DriverManagerDataSource dataSource = new DriverManagerDataSource();
            dataSource.setDriverClassName("com.mysql.jdbc.Driver");
            dataSource.setUrl("jdbc:mysql://10.10.1.63:3306/database2?characterEncoding=UTF-8");
            dataSource.setUsername("fpuser");
            dataSource.setPassword("fpdb$123456");
    
            return dataSource;
        }
    
        @Primary
        @Bean(name = "profileTransactionManager")
        public PlatformTransactionManager commonTransactionManager() {
            JpaTransactionManager transactionManager = new JpaTransactionManager();
               transactionManager.setEntityManagerFactory(commonEntityManagerFactory());
            return transactionManager;
        }
    
        @Bean
        public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
            return new PersistenceExceptionTranslationPostProcessor();
        }
    }
    

    注入示例:

    @Autowired
    @Qualifier(value="profileEntityManager")
    protected EntityManager entityManager;
    
    @Override
    public EntityManager getEntityManager() {
        return entityManager;
    }
    

    【讨论】:

    • 我测试过,但还是同样的问题。
    • 您是否尝试从代码中删除 @Primary 注释并查看结果?
    【解决方案3】:

    您尚未将 "common" 定义为 unitName,并且您有两个 @Primary 注释。 尝试配置: @Bean(name = "common") 而不是 @Bean(name = "commonEntityManagerFactory")

    【讨论】:

    • 持久性单元名称通过factory.setPersistenceUnitName("profile")明确指定
    • 我的错 ;)。但是您仍然定义了两个 EntityManagerFactories 作为自动装配的默认候选对象。正如我所说,这可能会让春天感到困惑。根据@Primary 的文档:Indicates that a bean should be given preference when multiple candidates are qualified to autowire a single-valued dependency. If exactly one 'primary' bean exists among the candidates, it will be the autowired value.
    猜你喜欢
    • 1970-01-01
    • 2017-12-12
    • 2017-11-29
    • 2014-11-16
    • 2014-03-27
    • 2012-03-08
    • 1970-01-01
    • 2018-03-22
    • 2019-04-19
    相关资源
    最近更新 更多