web-dev-qa-db-fra.com

Base de données multiple avec Spring + Hibernate + JPA

J'essaie de configurer Spring + Hibernate + JPA pour travailler avec deux bases de données (MySQL et MSSQL).

Mon datasource-context.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:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
  http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
  http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"
 xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:util="http://www.springframework.org/schema/util">

 <!--
 Data Source config 
  -->
 <bean id="dataSource" class="org.Apache.commons.dbcp.BasicDataSource"
  destroy-method="close" p:driverClassName="${local.jdbc.driver}" p:url="${local.jdbc.url}"
  p:username="${local.jdbc.username}" p:password="${local.jdbc.password}">
 </bean>

 <bean id="dataSourceRemote" class="org.Apache.commons.dbcp.BasicDataSource"
  destroy-method="close" p:driverClassName="${remote.jdbc.driver}"
  p:url="${remote.jdbc.url}" p:username="${remote.jdbc.username}"
  p:password="${remote.jdbc.password}" />

 <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
  p:entity-manager-factory-ref="entityManagerFactory" />

 <!-- 
    JPA config   
    -->
 <tx:annotation-driven transaction-manager="transactionManager" />

 <bean id="persistenceUnitManager"
  class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="persistenceXmlLocations">
   <list value-type="Java.lang.String">
    <value>classpath*:config/persistence.local.xml</value>
    <value>classpath*:config/persistence.remote.xml</value>
   </list>
  </property>

  <property name="dataSources">
   <map>
    <entry key="localDataSource" value-ref="dataSource" />
    <entry key="remoteDataSource" value-ref="dataSourceRemote" />
   </map>
  </property>
  <property name="defaultDataSource" ref="dataSource" />
 </bean>

 <bean id="entityManagerFactory"
  class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <property name="jpaVendorAdapter">
   <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
    p:showSql="true" p:generateDdl="true">
   </bean>
  </property>
  <property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="localjpa"/>
 </bean>

 <bean
  class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

</beans>

Chaque persistence.xml contient une unité, comme ceci:

<persistence-unit name="remote" transaction-type="RESOURCE_LOCAL">
  <properties>
   <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
   <property name="hibernate.dialect" value="${remote.hibernate.dialect}" />
   <property name="hibernate.hbm2ddl.auto" value="${remote.hibernate.hbm2ddl.auto}" />
  </properties>
 </persistence-unit>

La cause de PersistenceUnitManager est la suivante:

Impossible de résoudre la référence au bean 'persistenceUnitManager' lors du réglage propriété de haricot 'persistenceUnitManager'; imbriqué exception est org.springframework.beans.factory.BeanCreationException: Erreur lors de la création du bean avec le nom 'persistenceUnitManager' défini dans ressource de chemin de classe [config/datasource-context.xml]: L'initialisation du bean a échoué; imbriqué exception est org.springframework.beans.TypeMismatchException: Impossible de convertir la valeur de la propriété de tapez [Java.util.ArrayList] sur requis tapez [Java.lang.String] pour la propriété 'persistenceXmlLocation'; imbriqué exception est Java.lang.IllegalArgumentException: Impossible de convertir la valeur de type [Java.util.ArrayList] au type requis [Java.lang.String] pour la propriété 'persistenceXmlLocation': pas de correspondance éditeurs ou stratégie de conversion trouvés

S'il ne reste qu'un seul fichier persistence.xml, tout fonctionne correctement Mais il me faut 2 unités ...

J'essaie également de trouver une solution de remplacement pour le travail avec deux bases de données dans le contexte Spring + Hibernate. J'apprécierais donc toute solution.

Nouvelle erreur après le passage à persistenceXmlLocations:

Aucune unité de persistance par défaut définie dans {classpath: config/persistence.local.xml, classpath: config/persistence.remote.xml}

Mettre à jour: 

J'ajoute persistenceUnitName, cela fonctionne, mais avec une seule unité, toujours besoin d'aide.

Mettre à jour:

J'ai changé les fichiers de configuration: Datasource-context.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:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd"
    xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util">

    <bean id="dataSource" class="org.Apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${local.jdbc.driver}" p:url="${local.jdbc.url}"
        p:username="${local.jdbc.username}" p:password="${local.jdbc.password}">
    </bean>

    <bean id="dataSourceRemote" class="org.Apache.commons.dbcp.BasicDataSource"
        destroy-method="close" p:driverClassName="${remote.jdbc.driver}"
        p:url="${remote.jdbc.url}" p:username="${remote.jdbc.username}"
        p:password="${remote.jdbc.password}">
    </bean>

    <bean
        class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor">
        <property name="defaultPersistenceUnitName" value="pu1" />
    </bean>

    <bean id="persistenceUnitManager"
        class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
        <property name="persistenceXmlLocation" value="${persistence.xml.location}" />
        <property name="defaultDataSource" ref="dataSource" /> <!-- problem -->
        <property name="dataSources">
            <map>
                <entry key="local" value-ref="dataSource" />
                <entry key="remote" value-ref="dataSourceRemote" />
            </map>
        </property>
    </bean>

    <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
                p:showSql="true" p:generateDdl="true">
            </bean>
        </property>
        <property name="persistenceUnitManager" ref="persistenceUnitManager" />
        <property name="persistenceUnitName" value="pu1" />
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="entityManagerFactoryRemote"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
                p:showSql="true" p:generateDdl="true">
            </bean>
        </property>
        <property name="persistenceUnitManager" ref="persistenceUnitManager" />
        <property name="persistenceUnitName" value="pu2" />
        <property name="dataSource" ref="dataSourceRemote" />
    </bean>

    <tx:annotation-driven />

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
        p:entity-manager-factory-ref="entityManagerFactory" />


    <bean id="transactionManagerRemote" class="org.springframework.orm.jpa.JpaTransactionManager"
        p:entity-manager-factory-ref="entityManagerFactoryRemote" />

</beans>

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
    version="1.0">

    <persistence-unit name="pu1" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
            <property name="hibernate.dialect" value="${local.hibernate.dialect}" />
            <property name="hibernate.hbm2ddl.auto" value="${local.hibernate.hbm2ddl.auto}" />                          
        </properties>
    </persistence-unit>

    <persistence-unit name="pu2" transaction-type="RESOURCE_LOCAL">
        <properties>
            <property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.DefaultNamingStrategy" />
            <property name="hibernate.dialect" value="${remote.hibernate.dialect}" />
            <property name="hibernate.hbm2ddl.auto" value="${remote.hibernate.hbm2ddl.auto}" />
        </properties>
    </persistence-unit>

</persistence>

Maintenant, il construit deux entityManagerFactory, mais les deux sont pour Microsoft SQL Server

[main] INFO org.hibernate.ejb.Ejb3Configuration - Processing PersistenceUnitInfo [
    name: pu1
    ...]
[main] INFO org.hibernate.cfg.SettingsFactory - RDBMS: Microsoft SQL Server

[main] INFO org.hibernate.ejb.Ejb3Configuration - Processing PersistenceUnitInfo [
    name: pu2
    ...]
[main] INFO org.hibernate.cfg.SettingsFactory - RDBMS: Microsoft SQL Server (but must MySQL)

Je suggère que l'utilisation uniquement de dataSource, dataSourceRemote (pas de substitution) n'est pas travaillée. C'est mon dernier problème.

30
ziftech

Vous devez utiliser la propriété persistenceXmlLocations (notez le pluriel) plutôt que persistenceXmlLocation. C'est un tableau de chaînes, il sera donc automatiquement converti à partir de list:

<bean id="persistenceUnitManager"
      class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
  <property name="persistenceXmlLocations"><list>
    <value>classpath*:config/persistence.local.xml</value>
    <value>classpath*:config/persistence.remote.xml</value>
  </list></property>
  ...

Mise à jour (basé sur l'édition)

Votre entityManagerFactory ne spécifie pas la propriété persistenceUnitName. Vous devez le faire explicitement car vous définissez plusieurs unités de persistance et entityManagerFactory doit savoir laquelle utiliser.

15
ChssPly76

Justin, le numéro 3 peut être fait de manière plus standard comme ceci:

  1. Dans votre contexte de printemps:

    <context:annotation-config />
    
  2. Dans vos DAO gérés par Spring (notez la propriété unitName):

    @PersistenceContext(unitName = "pu1"`) protected EntityManager entityManager;
    

Ainsi, un EntityManager correctement connecté correspondant à l'unité de persistance nommée "pu1" serait injecté dans les DAO correspondantes.

8
Cristian Ebbens

Si vous suivez ce didacticiel, http://www.javacodegeeks.com/2010/05/jboss-42x-spring-3-jpa-hibernate.html vous pouvez apporter les modifications suivantes pour accéder à deux bases de données:

  1. persistence.xml, définissez une deuxième unité de pesée pour votre deuxième base de données.
  2. spring.xml, définissez un deuxième bean entityManagerFactory sous un nom différent, disons "entityManagerFactoryDB2" et configurez-le pour utiliser l'unité persistante pour la deuxième base de données.
  3. pour chaque DAO auquel vous souhaitez accéder, vous devez notamment:

    @Autowired
    private EntityManagerFactory entityManagerFactoryDB2;
    
    @PostConstruct
    public void init() {
        super.setEntityManagerFactory(entityManagerFactoryDB2);
    }
    

C'est tout!

Lors des cours de printemps, utilisez les DAO comme d'habitude!

6
Justin Cater

Consultez cette page wiki http://code.google.com/p/gwt-spring-jpa-lucene/wiki/PersistenceUnitSetup qui explique comment configurer spring avec persistenceXmlLocations et les annotations dans DAO

0
Giulio Roggero
  1. créez plusieurs entityManagerFactory correspondant à chaque unité de persistance. 
  2. spécifiez la propriété unitName pour @PersistenceContext 

basculer entre ceux entity entityageragerFactories ceux qui seront injectés

0
Amol Dixit