如何使用Spring和JPA设置多个数据源

时间:2018-04-20 03:05:07

标签: java spring jpa jndi entitymanager

在我们的应用程序中,我们希望使用Spring和JPA设置多个数据源。因此我们创建了2个entityManagerFactory,2个数据源和2个事务管理器。

的web.xml

CREATE VIEW view_name AS
SELECT cast(column as integer) as column
FROM table;

的persistence.xml

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

a_spring.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>

我还将另一个entityManagetFactory,Transaction Manager和dataSource声明为 b_spring.xml

错误

  

bean初始化失败;嵌套异常是   org.springframework.beans.factory.NoSuchBeanDefinitionException:没有   [javax.persistence.EntityManagerFactory]类型的唯一bean是   定义:预期单个bean但发现2引起:   org.springframework.beans.factory.NoSuchBeanDefinitionException:没有   [javax.persistence.EntityManagerFactory]类型的唯一bean是   定义:预期的单个bean,但发现2个   org.springframework.beans.factory.BeanFactoryUtils.beanOfTypeIncludingAncestors(BeanFactoryUtils.java:303)     在   org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findDefaultEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:451)     在   org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor.findEntityManagerFactory(PersistenceAnnotationBeanPostProcessor.java:428)     在   org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor $ AnnotatedMember.resolveEntityManager(PersistenceAnnotationBeanPostProcessor.java:582)     在   org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor $ AnnotatedMember.resolve(PersistenceAnnotationBeanPostProcessor.java:553)     在   org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor $ AnnotatedMember.inject(PersistenceAnnotationBeanPostProcessor.java:489)

4 个答案:

答案 0 :(得分:7)

如果有多个数据源配置,我们需要定义哪一个将被视为主数据源。我们可以指定在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"/>

答案 1 :(得分:1)

您是否尝试提供包含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" />

答案 2 :(得分:1)

您发布的错误消息表明您为类型为EntityManagerFactory的对象按类型自动装配。到目前为止,您所显示的代码都没有包含这样的注入,这意味着它可能在您尚未发布的某些代码中。

如果您要发布错误的完整堆栈跟踪,您将能够向上移动堆栈以查看哪个bean包含对EntityManagerFactory对象的不可满足的引用,这反过来会让您更改引用它以允许引用您想要的特定bean。

<强>更新

根据您提供的更多信息(谢谢)和一些Google搜索,似乎其他用户同样发现指定unitName不足以获得正确的EntityManager注入。几篇帖子在线备份@ lucid建议使用@Qualifier注释让Spring选择正确的bean,但遗憾的是that annotation was introduced in 2.5所以只有你升级才能使用它。 (考虑到你正在使用的Spring框架的年龄,这可能是一个好主意,但这是一个单独的对话。)

但是,several users have indicated在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中运行。

答案 3 :(得分:0)

有些事情对我来说并不好看。 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继承的extend语句

另外,我注意到PersistenceContext注释有另一个参数https://docs.oracle.com/javaee/6/api/javax/persistence/PersistenceContext.html,因此您可以尝试使用该名称来匹配bean定义中的id。