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:
persistence.xml
; EntityManager
s and TransactionsManager
s; 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.