问题
I'm trying to use Spring Data JPA with 2 databases in project. But an exception is triggered when I'm trying to run the application:
07:21:47.734 [main] ERROR o.s.web.context.ContextLoader - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'deviceRepository': Injection of persistence dependencies failed; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.persistence.EntityManagerFactory] is defined: expected single bean but found 2
at org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.postProcessPropertyValues(PersistenceAnnotationBeanPostProcessor.java:342) ~[spring-orm-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1106) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294) ~[spring-beans-3.1.0.RELEASE.jar:3.1.0.RELEASE]
...
Here is my applicationContext.xml
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource1">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url1}"/>
<property name="username" value="${database.username1}"/>
<property name="password" value="${database.password1}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager1">
<property name="entityManagerFactory" ref="entityManagerFactory1"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager1"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory1">
<property name="persistenceUnitName" value="persistenceUnit1"/>
<property name="dataSource" ref="dataSource1"/>
</bean>
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource2">
<property name="driverClassName" value="${database.driverClassName}"/>
<property name="url" value="${database.url2}"/>
<property name="username" value="${database.username2}"/>
<property name="password" value="${database.password2}"/>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
<property name="testWhileIdle" value="true"/>
<property name="timeBetweenEvictionRunsMillis" value="1800000"/>
<property name="numTestsPerEvictionRun" value="3"/>
<property name="minEvictableIdleTimeMillis" value="1800000"/>
<property name="validationQuery" value="SELECT 1"/>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager2">
<property name="entityManagerFactory" ref="entityManagerFactory2"/>
</bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager2"/>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory2">
<property name="persistenceUnitName" value="persistenceUnit2"/>
<property name="dataSource" ref="dataSource2"/>
</bean>
Here is my DAO interface:
@Repository
public interface DeviceRepository extends JpaRepository<Device, DevicePK>,
JpaSpecificationExecutor<Device> {
}
I've read a lot about @PersistenceContext but I never saw usages with JpaRepository.
回答1:
Well you do have 2 entitymanagers. I've never used JPARepository, but if it works close to its counter parts on spring-data for nosql, Spring will enhance the class, and probably inject the EM on it. Your problem is that you have 2 EM declared.
Have a look at the spring-jpa docs, they'll show you how to configure the repository for how you can add specific EMF to your repos
回答2:
Long story short:
You have to create custom implementation of that interface and that implementation has to contain entity manager declared as:
@PersistenceContext(unitName = "persistenceUnit1")
private EntityManager entityManager;
if you want to use persistence unit 1.
Check this out: http://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/repositories.html#repositories.custom-implementations, it also has examples and example 1.17 (little bit down the page) implements interface and has entity manager in it and that entity manager is passed on to super constructor.
You may also take a look at Spring Data - JPA, customizing Repository not working, it has implementation of interface that extends JpaRepository and it also has entity manager declared in implementation. Just add unitName to @PersistenceContext annotation and try it that way.
You may not need any custom methods (so your interface can be empty) but you do need constructor that passes on entity manager and all that tinkering with extending your own interface to bypass default automatic wiring behaviour.
回答3:
One of the two datasource must be defined as primary.
<bean>
has a primary attribute that can be set to true or false:
<bean primary="true|false"/>
Usually in @Configuration
the @Primary
annotation is placed to:
EntityManager
DataSource
TransactionManager
So you can try to add primary="true"
to the following beans:
dataSource1
transactionManager1
entityManagerFactory1
来源:https://stackoverflow.com/questions/9893274/multiple-databases-with-spring-data-jpa