1

Goal: Access multiple persistence units / datasources via @PersistenceContext.

Problem: Not fluent in spring xml configurations. Registering multiple datasources appears to require multiple EntityManagerFactories, which then leads to an error, stating that EntityManagerFactory isn't unique. I tried two EntityManagerFactories with an abstract parent one, because I can't add multiple datasources instead of the single datasource in the entityManagerFactory definition. How can I fix this?

I can't use SpringBoot or JpaRepositories. Spring-jdbc and orm are used with version 4.3.4.RELEASE, spring-data-jpa with version 1.10.5.RELEASE.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'aDaoImpl': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:357)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1219)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:551)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:754)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:866)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:542)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:128)
    at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:108)
    at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:251)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
    ... 24 more
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1034)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:981)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:579)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:546)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:707)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor$PersistenceElement.getResourceToInject(PersistenceAnnotationBeanPostProcessor.java:680)
    at org.springframework.beans.factory.annotation.InjectionMetadata$InjectedElement.inject(InjectionMetadata.java:169)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
    at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:354)
    ... 40 more

The current path from service to database consists of the following files. Note that this only shows the try for one datasource. Another one will be added once the error above is resolved.

Dao:

public class Dao {

    @PersistenceContext(name= "puName") // tried unitName=... as well
    protected EntityManager em;

    ...

Test that uses the Dao:

@ContextConfiguration("classpath:beans-context.xml")
public class DaoTest extends AbstractTransactionalJUnit4SpringContextTests {

    @Autowired
    private Dao testable;

    @PersistenceContext(name= "puName") // tried unitName=... as well
    protected EntityManager em;

    ...

beans-config.xml:

...
<import resource="db-context.xml"/>
...

db-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">

    <bean id="dataSource1" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>
    <bean id="dataSource2" class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:test2;DB_CLOSE_DELAY=-1"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>

    <bean id="entityManagerFactory" parent="abstractEntityManagerFactory">
        <property name="dataSource" ref="dataSource1"/>
        <property name="persistenceUnitName" value="puName"/>
    </bean>
    <!-- this causes the NoUniqueBeanDefinitionException -->
    <bean id="entityManagerFactory-2" parent="abstractEntityManagerFactory">
        <property name="dataSource" ref="dataSource2"/>
        <property name="persistenceUnitName" value="puName2"/>
    </bean>

    <bean id="abstractEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
            abstract="true">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="databasePlatform" value="org.hibernate.dialect.H2Dialect"/>
            </bean>
        </property>
    </bean>

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"/>

</beans>

Update:

I tried adding @Qualifier but I still the NoUniqueBeanDefinitionException ... expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2.

@PersistenceContext(name = "puName")
@Qualifier("entityManagerFactory")
protected EntityManager em;

Update:

Extending the spring-config with component scan does not change the error.

beans-config.xml:

<context:component-scan annotation-config="true" base-package="path.to.package"/>
<import resource="db-context.xml"/>

Update: Method injection instead of field injection doesn't change the error.

3
  • Have you tried adding a name to your bean definition as well as your injection? Commented Jun 1, 2017 at 16:34
  • If you can't use Repositories, why is this tagged spring-data? Commented Jun 2, 2017 at 4:37
  • @JensSchauder removed the wrong tag Commented Jun 2, 2017 at 6:02

1 Answer 1

2

Your code contains two ambiguities:

  1. Unit resolution for @PersistenceContext.
  2. Unit resolution for JpaTransactionManager.

To resolve the ambiguity for @PersistenceContext use @PersistenceContext(unitName = …) instead of @PersistenceContext(name = …)

@PersistenceContext(unitName = "puName")
protected EntityManager em1;

@PersistenceContext(unitName = "puName2")
protected EntityManager em2;

JpaTransactionManager requires as well a hint otherwise initialization fails with

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'javax.persistence.EntityManagerFactory' available: expected single matching bean but found 2: entityManagerFactory,entityManagerFactory-2
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveNamedBean(DefaultListableBeanFactory.java:1034)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:335)
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.findEntityManagerFactory(EntityManagerFactoryUtils.java:143)
    at org.springframework.orm.jpa.JpaTransactionManager.setBeanFactory(JpaTransactionManager.java:292)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1602)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
    ... 38 more

So one approach fixing the ambiguity is by setting the persistenceUnitName

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="persistenceUnitName" value="puName" />
</bean>
Sign up to request clarification or add additional context in comments.

1 Comment

YES THANK YOU! That did it. For all others reading this: Note the combination @PersistenceContext with the parameter unitName. It is important to have exactly this one.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.