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



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



Паутина.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>


А_спринг.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 .



Ошибка




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


574   4  

4 ответов:

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

Поскольку в 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?

Вы можете предоставить сведения о пакете в качестве свойства в определении 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, что, в свою очередь, позволит вам изменить способ работы. ссылка на него, чтобы разрешить ссылку на конкретный боб, который вы хотите.

Обновить

Основываясь на дополнительной информации, которую вы предоставили (спасибо), и некоторых гуглах, похоже, что другие пользователи также обнаружили, что указание unitName недостаточно для ввода правильного 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 и удаление оператора extend, наследующего от BaseService

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

Comments

    Ничего не найдено.