设置多个 JPA 数据源时出现 NoUniqueBeanDefinitionException
NoUniqueBeanDefinitionException when setting up multiple JPA datasources
我已经学习了很多教程并查看了很多答案(在 SO 和其他网站上),我非常有信心我没有遗漏任何东西,但我无法让两个 datasources/EntityManagers 工作在我的环境中。
这就是我的
DbADataSourceConfig.java
package com.myorg.rest.config.dba;
import ...
@Configuration
// @EnableJpaRepositories(
// basePackages = "com.myorg.rest.dao.dbA",
// entityManagerFactoryRef = "dbAEntityManager",
// transactionManagerRef = "dbATransactionManager"
// )
@EnableTransactionManagement
public class DbADataSourceConfig {
@Autowired
private EnvProperties settings;
@Bean
@Primary
public DataSource prjDataSource() {
DataSourceProperties ds = settings.getdbADatasource();
return ds.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
@Bean(name = "dbAEntityManager")
@Primary
public LocalContainerEntityManagerFactoryBean dbAEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(prjDataSource());
em.setPackagesToScan(new String[] { "com.myorg.model.entities.dba" });
em.setPersistenceUnitName("dbAUnit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
// em.afterPropertiesSet();
return em;
}
@Bean(name = "dbATransactionManager")
@Primary
public PlatformTransactionManager dbATransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(dbAEntityManager().getObject());
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
DbBDataSourceConfig.java
package com.myorg.rest.config.dbb;
import ...
@Configuration
// @EnableJpaRepositories(
// basePackages = "com.myorg.rest.dao.dbB",
// entityManagerFactoryRef = "dbBEntityManager",
// transactionManagerRef = "dbBTransactionManager"
// )
@EnableTransactionManagement
public class DbBDataSourceConfig {
@Autowired
private EnvProperties settings;
@Bean
@Primary
public DataSource prjDataSource() {
DataSourceProperties ds = settings.getdbBDatasource();
return ds.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
@Bean(name = "dbBEntityManager")
@Primary
public LocalContainerEntityManagerFactoryBean dbBEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(prjDataSource());
em.setPackagesToScan(new String[] { "com.myorg.model.entities.dbb" });
em.setPersistenceUnitName("dbBUnit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
// em.afterPropertiesSet();
return em;
}
@Bean(name = "dbBTransactionManager")
@Primary
public PlatformTransactionManager dbBTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(dbBEntityManager().getObject());
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
AbstractDBADAO.java
package com.myorg.rest.dao.dba.base;
public abstract class AbstractDBADAO<T extends Serializable> implements IAbstractJpaDAO<T> {
private Class<T> clazz;
@PersistenceContext(unitName = "dbAUnit")
private EntityManager entityManager;
public AbstractDBADAO(Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T findOne(String id) {
return entityManager.find(clazz, id);
}
public List<T> findAll() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<T> entityQuery = criteriaBuilder.createQuery(clazz);
entityQuery.from(clazz);
return entityManager.createQuery(entityQuery).getResultList();
}
public void create(T entity) {
entityManager.persist(entity);
}
public T update(T entity) {
return entityManager.merge(entity);
}
public void delete(T entity) {
entityManager.remove(entity);
}
public void deleteById(String entityId) {
T entity = findOne(entityId);
delete(entity);
}
}
最后 IAbstractJpaDAO.java
package com.myorg.rest.dao.dba.base;
import ...
public interface IAbstractJpaDAO<T extends Serializable> {
T findOne(String id);
List<T> findAll();
void create(T entity);
T update(T entity);
void delete(T entity);
void deleteById(String entityId);
}
当然,还有一堆@Repository
扩展IAbstractDAO
接口和相应的一堆@Service
扩展AbstractDAO<T>
,但那些只是骨架
EntityARepo.java
package com.myorg.rest.dao.dba.repositories;
import ...
@Repository
public interface EntityARepo extends IAbstractJpaDAO<EntityA> {
}
EntityAService.java
package com.myorg.rest.dao.dba.services;
import ...
@Service
public class EntityAService extends AbstractDBADAO<EntityA> implements EntityARepo {
public EntityAService() {
super(EntityA.class);
}
}
同样,为第二个数据库 (dbB) 设置了一大堆类。
问题
无论我做什么,我都会遇到以下问题(或非常相似的问题):
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:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1285)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
据我了解,@PersistenceContext
无法解析为正确的 LocalContainerEntityManagerFactoryBean
。都是setPersistenceUnitName('dbXUnit')
,所以应该能正确解析吧?
我没有任何 persistence.xml
文件,我正在以编程方式执行所有操作。
到目前为止我尝试了什么
- 很明显,上面的代码。
- 此外,您会注意到
@EnableJpaRepositories
有一个注释部分;那也不管用。
- 我还尝试为每个数据源配置 类 构建一个
PersistenceUnitManager
,但没有成功。
- 我试过
@Autowired
,有和没有 @PersistenceContext
,也没有运气。
- 我已经在 setter 上尝试了
@PersistenceContext
并在输入 EntityManager
上使用了 @Qualifier
,也没成功。
- 我试过使用和不使用
@Primary
装饰器。
请记住,上面发布的文件之间的任何不一致肯定是 copy/paste 错误,为了保密,我不得不编辑名称。另请注意,我编译、运行的代码除了上面列出的错误外,没有输出任何其他错误。此外,只设置了其中一个数据库配置 类,项目按预期运行,我可以在该连接上执行测试。
问题
- 谁能看出为什么
@PersistenceContext
没有连接
正确的依赖并抱怨重复?或
- 我应该以完全不同的方式做事吗?
到目前为止你走的路是正确的。
你需要每个 2 个:
- EntityManager/factory
DataSource
TransactionManager
- JPARepository-Configs
成功的关键是 IMO 正确且唯一地命名它们 (2x4=8 个不同的名称)。 @Primary
和 @Secondary
在这里没有帮助。
我已经学习了很多教程并查看了很多答案(在 SO 和其他网站上),我非常有信心我没有遗漏任何东西,但我无法让两个 datasources/EntityManagers 工作在我的环境中。
这就是我的
DbADataSourceConfig.java
package com.myorg.rest.config.dba;
import ...
@Configuration
// @EnableJpaRepositories(
// basePackages = "com.myorg.rest.dao.dbA",
// entityManagerFactoryRef = "dbAEntityManager",
// transactionManagerRef = "dbATransactionManager"
// )
@EnableTransactionManagement
public class DbADataSourceConfig {
@Autowired
private EnvProperties settings;
@Bean
@Primary
public DataSource prjDataSource() {
DataSourceProperties ds = settings.getdbADatasource();
return ds.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
@Bean(name = "dbAEntityManager")
@Primary
public LocalContainerEntityManagerFactoryBean dbAEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(prjDataSource());
em.setPackagesToScan(new String[] { "com.myorg.model.entities.dba" });
em.setPersistenceUnitName("dbAUnit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
// em.afterPropertiesSet();
return em;
}
@Bean(name = "dbATransactionManager")
@Primary
public PlatformTransactionManager dbATransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(dbAEntityManager().getObject());
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
DbBDataSourceConfig.java
package com.myorg.rest.config.dbb;
import ...
@Configuration
// @EnableJpaRepositories(
// basePackages = "com.myorg.rest.dao.dbB",
// entityManagerFactoryRef = "dbBEntityManager",
// transactionManagerRef = "dbBTransactionManager"
// )
@EnableTransactionManagement
public class DbBDataSourceConfig {
@Autowired
private EnvProperties settings;
@Bean
@Primary
public DataSource prjDataSource() {
DataSourceProperties ds = settings.getdbBDatasource();
return ds.initializeDataSourceBuilder().type(BasicDataSource.class).build();
}
@Bean(name = "dbBEntityManager")
@Primary
public LocalContainerEntityManagerFactoryBean dbBEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(prjDataSource());
em.setPackagesToScan(new String[] { "com.myorg.model.entities.dbb" });
em.setPersistenceUnitName("dbBUnit");
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
// em.afterPropertiesSet();
return em;
}
@Bean(name = "dbBTransactionManager")
@Primary
public PlatformTransactionManager dbBTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(dbBEntityManager().getObject());
return transactionManager;
}
Properties additionalProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
AbstractDBADAO.java
package com.myorg.rest.dao.dba.base;
public abstract class AbstractDBADAO<T extends Serializable> implements IAbstractJpaDAO<T> {
private Class<T> clazz;
@PersistenceContext(unitName = "dbAUnit")
private EntityManager entityManager;
public AbstractDBADAO(Class<T> clazzToSet) {
this.clazz = clazzToSet;
}
public T findOne(String id) {
return entityManager.find(clazz, id);
}
public List<T> findAll() {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<T> entityQuery = criteriaBuilder.createQuery(clazz);
entityQuery.from(clazz);
return entityManager.createQuery(entityQuery).getResultList();
}
public void create(T entity) {
entityManager.persist(entity);
}
public T update(T entity) {
return entityManager.merge(entity);
}
public void delete(T entity) {
entityManager.remove(entity);
}
public void deleteById(String entityId) {
T entity = findOne(entityId);
delete(entity);
}
}
最后 IAbstractJpaDAO.java
package com.myorg.rest.dao.dba.base;
import ...
public interface IAbstractJpaDAO<T extends Serializable> {
T findOne(String id);
List<T> findAll();
void create(T entity);
T update(T entity);
void delete(T entity);
void deleteById(String entityId);
}
当然,还有一堆@Repository
扩展IAbstractDAO
接口和相应的一堆@Service
扩展AbstractDAO<T>
,但那些只是骨架
EntityARepo.java
package com.myorg.rest.dao.dba.repositories;
import ...
@Repository
public interface EntityARepo extends IAbstractJpaDAO<EntityA> {
}
EntityAService.java
package com.myorg.rest.dao.dba.services;
import ...
@Service
public class EntityAService extends AbstractDBADAO<EntityA> implements EntityARepo {
public EntityAService() {
super(EntityA.class);
}
}
同样,为第二个数据库 (dbB) 设置了一大堆类。
问题
无论我做什么,我都会遇到以下问题(或非常相似的问题):
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:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1285)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
据我了解,@PersistenceContext
无法解析为正确的 LocalContainerEntityManagerFactoryBean
。都是setPersistenceUnitName('dbXUnit')
,所以应该能正确解析吧?
我没有任何 persistence.xml
文件,我正在以编程方式执行所有操作。
到目前为止我尝试了什么
- 很明显,上面的代码。
- 此外,您会注意到
@EnableJpaRepositories
有一个注释部分;那也不管用。 - 我还尝试为每个数据源配置 类 构建一个
PersistenceUnitManager
,但没有成功。 - 我试过
@Autowired
,有和没有@PersistenceContext
,也没有运气。 - 我已经在 setter 上尝试了
@PersistenceContext
并在输入EntityManager
上使用了@Qualifier
,也没成功。 - 我试过使用和不使用
@Primary
装饰器。
请记住,上面发布的文件之间的任何不一致肯定是 copy/paste 错误,为了保密,我不得不编辑名称。另请注意,我编译、运行的代码除了上面列出的错误外,没有输出任何其他错误。此外,只设置了其中一个数据库配置 类,项目按预期运行,我可以在该连接上执行测试。
问题
- 谁能看出为什么
@PersistenceContext
没有连接 正确的依赖并抱怨重复?或 - 我应该以完全不同的方式做事吗?
到目前为止你走的路是正确的。
你需要每个 2 个:
- EntityManager/factory
DataSource
TransactionManager
- JPARepository-Configs
成功的关键是 IMO 正确且唯一地命名它们 (2x4=8 个不同的名称)。 @Primary
和 @Secondary
在这里没有帮助。