Как настроить несколько источников данных с Spring и JPA

В нашем приложении мы хотим установить несколько источников данных с Spring и JPA. Поэтому мы создали 2 entityManagerFactory, 2 источника данных и 2 transaction - manager.

web.в XML

 <param-value>
    /WEB-INF/a_spring.xml
    /WEB-INF/b_spring.xml
 </param-value>

настойчивость.в 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, диспетчер транзакций и источник данных b_spring.в XML.

инициализация компонента не удалась; вложенное исключение орг.springframework.зернышки.фабрика.NoSuchBeanDefinitionException: Нет уникальный Боб типа [javax.стойкость.EntityManagerFactory] является определены: ожидаемые зернышко, но нашли 2 вызвана: орг.springframework.зернышки.фабрика.NoSuchBeanDefinitionException: Нет уникальный Боб типа [javax.стойкость.EntityManagerFactory] является определено: ожидается зернышко а нашел 2 в орг.springframework.зернышки.фабрика.BeanFactoryUtils.beanOfTypeIncludingAncestors (BeanFactoryUtils.java: 303) на орг.springframework.ОЗР.jpa.поддержка.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory (PersistenceAnnotationBeanPostProcessor.java: 451) на орг.springframework.ОЗР.jpa.поддержка.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory (PersistenceAnnotationBeanPostProcessor.java: 428) на орг.springframework.ОЗР.jpa.поддержка.PersistenceAnnotationBeanPostProcessor$AnnotatedMember.resolveEntityManager (PersistenceAnnotationBeanPostProcessor.java: 582) на орг.springframework.ОЗР.jpa.поддержка.PersistenceAnnotationBeanPostProcessor$AnnotatedMember.resolve (PersistenceAnnotationBeanPostProcessor.java: 553) на орг.springframework.ОЗР.jpa.поддержка.PersistenceAnnotationBeanPostProcessor$AnnotatedMember.inject (PersistenceAnnotationBeanPostProcessor.java: 489)

4 ответов


в случае конфигурации с несколькими источниками данных нам нужно определить, какой из них будет считаться основным источником данных. мы можем указать это, используя @Primary аннотация в конфигурации java или primary=true в конфигурации компонента XML.

поскольку в XML создается два менеджера сущностей, нам нужно использовать @Qualifier указать, какой компонент должен быть введен где. В твоем случае, что-то вроде этого.

@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 -

<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. Ни один из кода, который вы показали до сих пор, не содержит такой инъекции, что означает, что он, вероятно, в каком-то коде, который вы еще не опубликовали.

Если бы вы разместили полную трассировку стека ошибки, вы могли бы подняться по стеку, чтобы увидеть, какой компонент содержит неудовлетворительную ссылку на объект EntityManagerFactory, который, в свою очередь, позволит вам изменить способ вы ссылаетесь на него, чтобы разрешить ссылку на конкретный компонент, который вы хотите.

обновление

на основе дополнительной информации, которую вы предоставили (спасибо) и некоторые Гугля, кажется, что другие пользователи аналогичным образом обнаружили, что указание имени единицы недостаточно, чтобы получить правильный EntityManager. Несколько сообщений в интернете поддерживают рекомендацию @lucid использовать аннотацию @Qualifier, чтобы получить Spring для выбора правильного компонента, но, к сожалению что аннотация была введена в 2.5 поэтому он доступен только для вас, если вы обновляете. (Что, учитывая возраст весенней структуры, которую вы используете, вероятно, хорошая идея, но это отдельный разговор.)

, несколько пользователей указали что альтернативный подход доступен в 2.0.5, используя один PersistenceUnitManager, который ссылается на несколько источников данных, а не на несколько единиц сохранения, каждая из которых ссылается на один источник данных. Из официальных весенних документов: https://docs.spring.io/spring/docs/2.0.x/reference/orm.html#orm-jpa-multiple-pu.

в целом я бы предложил вам рассмотреть возможность обновления до версии Spring, которая не старше десяти лет, что позволит вам указать аннотацию @Qualifier на ответ @lucid. Но если по какой-то причине это невозможно, подход PersistenceUnitManager должен дать вам способ заставить его работать в Spring 2.0.5.


есть несколько вещей, которые не выглядят хорошо для меня. Имя сеттеров не будет соответствовать именам свойств, я думаю, что это важно, второе - о наследовании, некоторые аннотации иногда работают только в конкретных классах, а не в базовых классах. Я бы попытался изменить базовую службу следующим образом.

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 class и удалите инструкцию extend, которая наследуется от BaseService

кроме того, я заметил, что PersistenceContext аннотация имеет другой param https://docs.oracle.com/javaee/6/api/javax/persistence/PersistenceContext.html, поэтому вы можете попробовать использовать имя, а также соответствовать идентификатору в определении bean.