Multiple Persistence Units with Spring Data

Asked

Viewed 1,286 times

5

You can create multiple Units persistences by connecting to separate databases in the same JPA application using Spring Data? For example. I have an application that will run in Mysql normally. However, it will need to do a query in an Oracle database.

At first I thought of the following solution:

  1. Create two datasources on the application server (one for each database);
  2. Create two persistent Units on persistence.xml;
  3. Since I’m using Spring Data, it separates creation from EntityManagers and TransactionsManagers;
  4. Separate Daos packets that will use different databases so that Spring data knows which ones EntityManager;

Well, the problem starts when in deploy, Wildfly accuses that I can’t have more than one persistence unit 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

The Eclipse also accuses Warning in development time:

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

Now a little code. Below follows my persistence.xml, with two Units persistence. One pointing to Mysql and the other 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 altered the file jboss-web.xml. Look how it turned out:

<?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 benchmark development environment 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 rightly declaring more of a persistent Unit within the persistence.xml. If that violates any specifics, I don’t know yet. I’ve also seen a lot of manual stuff, i.e., declaring Unit persistence, creating the Entity Managers in hand and getting the same in the Daos hopefully As I’m using Spring Data, this is unfeasible for me.

Here you go an article by declaring more than one persistent Unit within the persistence.xml. Here you go other article declaring two persistent Unit in the persistence.xml.

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

UPDATE:

I’m adding the code to how I create the Entitymanagers. It is not exactly the same code as this application used above, but it is the same way and the same problem occurs. In the case below, I have three persistent Units (2 oracles 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 the injections of the MS in my DAO’s, is the Spring Data, which has support for multiple Persistance units, according to their documentation, but I have not found how to do it properly 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.

2 answers

4

(...) the problem starts when in deploy, Wildfly accuses that I don’t can have more than one persistence drive in the file persistence.xml.

Actually this is not what the error message accuses. See:

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.

In a nutshell, the mistake says: if you have more than one persistence Unit stated in the persistence.xml, then you have to specify which Unit persistence you want each time you want to access the database.

You have not shown your code that creates or introduces Entitymanager. If you for example inject the Entitymanager thus:

@PersistenceContext
private EntityManager em;

You should start injecting like this:

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

In short

When you have more than one persistence Unit you must indicate the name of which one you want to use each time you inject a Entitymanager or creates an instance of a Entitymanagerfactory.

  • Now it has begun to become clear to me. But the second part of your answer does not apply to me, the part of @PersistenceContext because who abstracted all this for me, is Spring Data. But anyway, what interests me, is where I declare unitName (since I use Spring Data) to specify which one I want to use. From what I understand, it is to specify a standard Unit when there was no stated, right?

  • @Ricardogiaviti You can update your question with the Java code where you get Entitymanager?

  • I will update. I don’t have the code here. But tonight, I update it right.

  • I updated my question with the XML I use to create Entity Managers. See if you can crack it. I also put an example of DAO. Thank you!

  • @Ricardogiaviti And where you consume PermissaoUsuarioDAO? I imagine that you declare a variable of this type and add an annotation to indicate that you want an instance to be injected. Or you reference permissaoUsuarioDAO directly on a JSF page?

  • It is consumed in the Service, thus: @Inject private PermissaoUsuarioDAO permissaoUsuarioDAO; and then you can use it. But there is no implementation of it.

Show 1 more comment

0

Hello, I am days ago looking for a solution to this injection problem of more than one Persistence Unit using spring data.

I came across the following solution:

comment on

<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 8.2.0.Final server and , as I use Maven, dependency :

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

was as <scope>provided</scope>

I removed that part.

In the spring Beans configuration I made the following modification:

OF

<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 names of the Entitymanagerfactory Beans I created as

<bean id="entityManagerFactory"...

Hibernate 4.3.0.Final

Spring 4.1.6.Final

Spring Data Jpa 1.8.0.RELEASE

For now I am managing to use both persistence Units. D:

Browser other questions tagged

You are not signed in. Login or sign up in order to post.