[英]How do I configure multiple JPA data sources using Spring @Configuration class?
[英]How to setup multiple data sources with Spring and JPA
在我們的應用程序中,我們希望使用Spring和JPA設置多個數據源。 因此我們創建了2個entityManagerFactory,2個數據源和2個事務管理器。
web.xml中
<param-value>
/WEB-INF/a_spring.xml
/WEB-INF/b_spring.xml
</param-value>
persistence.xml中
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="db1" transaction-type="RESOURCE_LOCAL">
<class>com.rh.domain.RcA</class>
</persistence-unit>
<persistence-unit name="db2" transaction-type="RESOURCE_LOCAL">
<class>com.rh.domain.Rcb</class>
</persistence-unit>
</persistence>
a_spring.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"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean id = "RcMaintenanceService" class="com.rh.services.RcAbcMaintenanceServiceImpl" autowire="byName" />
<aop:config>
<aop:pointcut id="rOperation" expression="execution(* com.rh.services.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="rOperation"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/db1" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="db1" />
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
</bean>
</property>
</bean>
我還將另一個entityManagetFactory,Transaction Manager和dataSource聲明為b_spring.xml 。
錯誤
bean的初始化失敗; 嵌套異常是org.springframework.beans.factory.NoSuchBeanDefinitionException:沒有定義類型為[javax.persistence.EntityManagerFactory]的唯一bean:期望的單個bean但找到2引起的:org.springframework.beans.factory.NoSuchBeanDefinitionException:沒有唯一的bean類型為[javax.persistence.EntityManagerFactory]的定義:預期的單個bean但在org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor的org.springframework.beans.factory.BeanFactoryUtils.beanOfTypeIncludingAncestors(BeanFactoryUtils.java:303)中找到2個。 findOfaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:451)atg.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:428)org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor $ AnnotatedMember.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java: 582)在org.springframework.orm.jpa.suppo orrt.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor $ AnnotatedMember.inject(PersistenceAnnotationBeanPostProcessor.java:489)中的rt.PersistenceAnnotationBeanPostProcessor $ AnnotatedMember.resolve(PersistenceAnnotationBeanPostProcessor.java:553)
在多數據源配置的情況下,我們需要定義哪一個將被視為主數據源。 我們可以指定在java配置中使用@Primary
注釋或在XML bean配置中使用primary=true
。
由於有兩個實體管理器是用XML創建的,我們需要使用@Qualifier
來指定應該將哪個bean注入到哪里。 在你的情況下,這樣的事情。
@PersistenceContext(unitName = "db1")
public void setEntityManager(@Qualifier("entityManagerFactory") EntityManager entityMgr) {
this.em = entityMgr;
}
對於XML配置,我們可以做這樣的事情
<bean id="BaseService" class="x.y.z.BaseService">
<property name="em" ref="entityManagerFactory"/>
<property name="em1" ref="entityManagerFactory1"/>
</bean>
<bean id = "RcMaintenanceService" class="com.rh.services.RcAbcMaintenanceServiceImpl" autowire="byName" parent="BaseService"/>
您是否嘗試提供包含EntityManagerFactory bean的包詳細信息?
您可以在bean定義中提供包詳細信息作為屬性 -
<property name="packagesToScan" value="com.XX.XX.XX.XX" />
要在此塊中添加的新屬性 -
<bean id="entityManagerFactory1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="db2" />
<property name="dataSource" ref="dataSource1"/>
<-- add here for both beans -->
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="database" value="MYSQL" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"/>
</bean>
</property>
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect">
</bean>
</property>
</bean>
此外,您缺少persistenceXmlLocation
屬性 -
<property name="persistenceXmlLocation" value="***/persistence.xml" />
您發布的錯誤消息表明您是按類型為EntityManagerFactory類型的對象自動裝配。 到目前為止,您所顯示的代碼都沒有包含這樣的注入,這意味着它可能在您尚未發布的某些代碼中。
如果您要發布錯誤的完整堆棧跟蹤,您將能夠向上移動堆棧以查看哪個bean包含對EntityManagerFactory對象的不可滿足的引用,這反過來可以讓您更改引用的方式它允許引用您想要的特定bean。
更新
根據您提供的進一步信息(謝謝)和一些谷歌搜索,似乎其他用戶同樣發現指定unitName不足以獲得正確的EntityManager注入。 幾篇帖子在線備份@ lucid建議使用@Qualifier注釋讓Spring選擇正確的bean,但不幸的是,這個注釋是在2.5中引入的,所以只有你升級才能使用它。 (考慮到你正在使用的Spring框架的年齡,這可能是一個好主意,但這是一個單獨的對話。)
但是, 一些用戶表示 2.0.5中提供了另一種方法,使用引用多個數據源的單個PersistenceUnitManager而不是每個引用單個數據源的多個持久性單元。 從官方的Spring文檔: https : //docs.spring.io/spring/docs/2.0.x/reference/orm.html#orm-jpa-multiple-pu 。
總的來說,我建議您考慮升級到不超過十年的Spring版本,這樣可以讓您根據@ lucid的答案指定@Qualifier注釋。 但是如果由於某種原因這是不可能的,那么PersistenceUnitManager方法應該為您提供一種方法,使其在Spring 2.0.5中運行。
有幾件事對我來說不太好看。 setter的名稱與屬性名稱不匹配,我認為這很重要,第二件事是關於繼承,有些注釋有時只適用於不在基類中的具體類。 我會嘗試更改基本服務,如下所示。
public class BaseService {
@PersistenceContext(unitName = "db2")
private EntityManager em;
@PersistenceContext(unitName = "db1")
private EntityManager em1;
public EntityManager getEm() {
return em;
}
protected EntityManager getEm2() {
return em1;
}
public void setEm(EntityManager entityMgr) {
this.em = entityMgr;
}
public void setEm1(EntityManager entityMgr) {
this.em = entityMgr;
}
}
如果這不起作用我可能會嘗試刪除基類,看看我是否將注釋放在我可以使其工作的具體類下,我會這樣做只是將注釋移動到RcAbcMaintenanceServiceImpl
類並刪除繼承自的繼承語句BaseService
另外,我注意到PersistenceContext
注釋有另一個參數https://docs.oracle.com/javaee/6/api/javax/persistence/PersistenceContext.html ,所以你可以嘗試使用這個名字來匹配id bean的定義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.