Multiple persistence units with Spring Data

5

Is it possible to create multiple persistences units by connecting to different databases in the same JPA application using Spring Data? For example. I have an application that will run on MySQL normally. However, it will have to query in an Oracle database.

At first I thought of the following solution:

  • Create two datasources on the application server (one for each bank);
  • Create two persistence units in persistence.xml ;
  • As I'm using Spring Data, it separates the creation of EntityManager s and TransactionsManager s;
  • Separate the DAO packages that will use the different banks so that Spring data knows what EntityManager ;
  • Well, the problem starts when deploy, WildFly complains that I can not have more than one persistence drive in the file persistence.xml :

    Caused by: java.lang.IllegalArgumentException: JBAS011470: Persistence unitName was not specified and there are 2 persistence unit definitions in application deployment deployment "authws.war".  Either change the application deployment to have only one persistence unit definition or specify the unitName for each reference to a persistence unit.
    at org.jboss.as.jpa.container.PersistenceUnitSearch.ambiguousPUError(PersistenceUnitSearch.java:187)
    at org.jboss.as.jpa.container.PersistenceUnitSearch.findWithinDeployment(PersistenceUnitSearch.java:153)
    at org.jboss.as.jpa.container.PersistenceUnitSearch.findPersistenceUnitSupplier(PersistenceUnitSearch.java:75)
    at org.jboss.as.jpa.container.PersistenceUnitSearch.resolvePersistenceUnitSupplier(PersistenceUnitSearch.java:64)
    at org.jboss.as.jpa.processor.JPAAnnotationProcessor.getPersistenceUnit(JPAAnnotationProcessor.java:372)
    at org.jboss.as.jpa.processor.JPAAnnotationProcessor.getBindingSource(JPAAnnotationProcessor.java:296)
    at org.jboss.as.jpa.processor.JPAAnnotationProcessor.processMethod(JPAAnnotationProcessor.java:206)
    at org.jboss.as.jpa.processor.JPAAnnotationProcessor.processPersistenceAnnotations(JPAAnnotationProcessor.java:143)
    at org.jboss.as.jpa.processor.JPAAnnotationProcessor.deploy(JPAAnnotationProcessor.java:100)
    at org.jboss.as.server.deployment.DeploymentUnitPhaseService.start(DeploymentUnitPhaseService.java:159) [wildfly-server-8.2.0.Final.jar:8.2.0.Final]
    ... 5 more
    

    Eclipse also accuses warning at development time:

    Multiple persistence units defined - only the first persistence unit will be recognized
    

    Now a little code. Below is my persistence.xml , with two persistence units. One pointing to MySQL and another pointing to Oracle.

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="2.1"
                 xmlns="http://xmlns.jcp.org/xml/ns/persistence"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence
                 http://www.oracle.com/webfolder/technetwork/jsc/xml/ns/persistence/persistence_2_1.xsd">
        <persistence-unit name="authwsPU" transaction-type="JTA">
            <jta-data-source>java:/datasource/authwsds</jta-data-source>
    
            ..My MySQL mapping classes...
    
            <properties>
                <!-- MySQL -->
                <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
    
                <property name="hibernate.show_sql" value="true"/>
                <property name="hibernate.hbm2ddl.auto" value="update"/>
                <property name="hibernate.id.new_generator_mappings" value="true"/>
                <property name="jboss.entity.manager.factory.jndi.name" value="java:jboss/authwsEMF" />
            </properties>
        </persistence-unit>
    
        <persistence-unit name="antaresPU" transaction-type="JTA">
            <jta-data-source>java:/datasource/antaresds</jta-data-source>
    
            ...My Oracle mapping classes...
    
            <properties>
                <property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
                <property name="hibernate.show_sql" value="true"/>
                <property name="hibernate.id.new_generator_mappings" value="true"/>
                <property name="jboss.entity.manager.factory.jndi.name" value="java:jboss/antaresEMF" />
            </properties>
        </persistence-unit>
    </persistence>
    

    And I also changed the file jboss-web.xml . Here's how it went:

    <?xml version="1.0" encoding="UTF-8"?>
    <jboss-web xmlns="http://www.jboss.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee
                                   http://www.jboss.org/j2ee/schema/jboss-web_5_1.xsd">
    
        <context-root>/authws</context-root>
    
        <persistence-context-ref id="autenticacaoCtx">
            <persistence-context-ref-name>auth_ws/authEMF</persistence-context-ref-name>
            <persistence-unit-name>authwsPU</persistence-unit-name>
        </persistence-context-ref>
    
        <persistence-context-ref id="antaresCtx">
            <persistence-context-ref-name>auth_ws/antaresEMF</persistence-context-ref-name>
            <persistence-unit-name>antaresPU</persistence-unit-name>
        </persistence-context-ref>
    </jboss-web>
    

    My development environment for reference is this:

    • JDK 8;
    • JPA 2.1 / Hibernate 4.3.7.Final;
    • WildFly 8.2.0.Final;
    • Spring Data 1.7.1.RELEASE

    I found some articles showing how to do this by declaring more than one persistence unit within persistence.xml . If this violates some specification, I do not know yet. I've also seen a lot of manual stuff, that is, declaring the persistence unit, creating the Entity Managers on hand and getting the same in DAOs as I'm using Spring Data, it's unfeasible for me.

    Here you have

    / a> showing of declaring more than one persistence unit within persistence.xml . Here's another article declaring two persistence units on persistence.xml .

    Anyway, if anyone knows how to do it, I appreciate it. My next step, which I have not tried is to use two persistence.xml . If I succeed, I'll come back here and update the question.

    UPDATE:

    I'm adding code to how I create the EntityManagers. It's not exactly the same code as that application used above, but it's the same form and the same problem occurs. In the case below, I'm having three persistence units (2 oracle and 1 MySQL).

    <!-- Obtém a conexão do Persistence que é feito deploy no AS -->
    <jee:jndi-lookup jndi-name="java:jboss/poEMF" id="poEntityManagerFactory" expected-type="javax.persistence.EntityManagerFactory" />
    <jpa:repositories base-package="br.com.po.dao" entity-manager-factory-ref="poEntityManagerFactory"  />
    
    <!-- Antares -->
    <jee:jndi-lookup jndi-name="java:jboss/antaresEMF" id="antaresEntityManagerFactory" expected-type="javax.persistence.EntityManagerFactory" />
    <jpa:repositories base-package="br.com.antares.dao" entity-manager-factory-ref="antaresEntityManagerFactory" />
    
    <!-- Antares -->
    <jee:jndi-lookup jndi-name="java:jboss/e1EMF" id="e1EntityManagerFactory" expected-type="javax.persistence.EntityManagerFactory" />
    <jpa:repositories base-package="br.com.e1.dao" entity-manager-factory-ref="e1EntityManagerFactory" />
    
    <!-- Especifica as configurações por anotações -->
    <tx:jta-transaction-manager  />
    <tx:annotation-driven />
    

    From here, who takes care of MS injections in my DAO's, is Spring Data, which supports multiple persistence units, according to their documentation, but I have not figured out how to do this correctly yet. >

    An example of DAO:

    @Repository
    public interface PermissaoUsuarioDAO extends
            JpaRepository<PermissaoUsuario, Long> {
    
        List<PermissaoUsuario> findByUsuario(Usuario usuario);
        List<PermissaoUsuario> findByAtividade(Atividade atividade);
        PermissaoUsuario findByUsuarioAndAtividade(Usuario usuario,
                Atividade atividade);
    }
    

    JPQLs are generated dynamically in the calls of these methods. This is the "magic" of Spring Data.

        

    asked by anonymous 15.01.2015 / 13:24

    2 answers

    4
      

    (...) the problem begins when deploy, WildFly accuses me that I do not   I can have more than one persistence drive in the file   persistence.xml.

    This is not really what the error message accuses. See:

      

    Caused by: java.lang.IllegalArgumentException: JBAS011470: Persistence   unitName was not specified and there are 2 persistence units   definitions in application deployment deployment "authws.war". Either   change the application deployment to have only one persistence unit   definition or specify the unitName for each reference to a persistence   unit.

    In a nutshell, the error says: If you have more than one persistence unit declared in persistence.xml , then you have to specify which persistence unit want every time you want to access the database.

    You have not shown your code that creates or integrates the EntityManager. If you for example inject the EntityManager like this:

    @PersistenceContext
    private EntityManager em;
    

    You should start injecting like this:

    @PersistenceContext(unitName = "nome_de_um_persistence_unit")
    private EntityManager em;
    

    Summarizing

    When you have more than one persistence unit you must indicate the name of which one you want to use each time you inject an EntityManager or create an instance of an EntityManagerFactory .

        
    15.01.2015 / 14:01
    0

    Hello, I've been looking for a solution to this problem of injecting more than one Persistence Unit using spring data for days.

    I came across the following solution:

    comment

    <subsystem xmlns="urn:jboss:domain:jpa:1.1">                                                                                                                              
                <jpa default-datasource="" default-extended-persistence-inheritance="DEEP"/>                                                                                              
    </subsystem>
    

    In the standalone.xml file of the Windfly server 8.2.0.Final e, as I use maven, the dependency:

    <dependency>
                <groupId>dom4j</groupId>
                <artifactId>dom4j</artifactId>
                <version>1.6.1</version>
    </dependency>
    

    I was like <scope>provided</scope>

    I removed this part.

    In the spring beans configuration I made the following modification:

    DE

    <jpa:repositories base-package="br.com.rbs.repository"/>
    

    FOR

    <jpa:repositories base-package="br.com.rbs.repository" entity-manager-factory-ref="entityManagerFactory" transaction-manager-ref="transactionManager"/>
    

    using the EntityManagerFactory beans names that I created as

    <bean id="entityManagerFactory"...
    

    Hibernate 4.3.0.Final

    Spring 4.1.6.Final

    Spring Data Jpa 1.8.0.RELEASE

    For the time being I am able to use both persistence units. : D

        
    14.07.2015 / 17:11