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:
- Create two datasources on the application server (one for each database);
- Create two persistent Units on
persistence.xml
; - Since I’m using Spring Data, it separates creation from
EntityManager
s andTransactionsManager
s; - 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.
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 declareunitName
(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?– humungs
@Ricardogiaviti You can update your question with the Java code where you get Entitymanager?
– Caffé
I will update. I don’t have the code here. But tonight, I update it right.
– humungs
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!
– humungs
@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 referencepermissaoUsuarioDAO
directly on a JSF page?– Caffé
It is consumed in the Service, thus:
@Inject private PermissaoUsuarioDAO permissaoUsuarioDAO;
and then you can use it. But there is no implementation of it.– humungs