簡體   English   中英

如何使用Spring和JPA設置多個數據源

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM