Composite persistence units - Java EE
The way to handle multiple entity managers, i.e. multiple persistence units, in Java EE is to use composite persistence units (CPUs). Such a composite persistence unit can be assessed from one single point in the EE web-application, a datalayer. This needs to be a @Stateless
EE bean though in order to work with the @PersistenceContext
.
Composite persistence units have been introduced to make possible reusing entity classes, among various Java applications. CPUs are a feature of Enterprise architecture. I choose to use EclipseLink as showcase, as I have positive experience with that from a running production application.
Introduction
In some cases, entities contain general data that is needed across more web-services in a server landscape. Take for example a general ‘name-address’ entity, a ‘user-password-role’ entity, a ‘document-keyword-index’ entity, etc. A composite persistence unit implementation facilitates that the source of each entity definition is specified in only one place (‘single point of definition’). These entity definitions can subsequently be included in each Java web-application that needs this entity access.
Working of composite persistence unit
The working of a composite persistence unit is illustrated by the following tutorial: EclipseLink composite persistence units
The concept of composite persistence units works by first defining member persistence units. Each member persistence unit may be associated with a different database, but the member persistence units can also all refer to the same actual database. I have experience with the latter, where EclipseLink (version 2.6.4) was used in combination with one Postgress database.
Maven is needed to make possible the required modular approach.
Settings in persistence.xml
A composite persistence unit member is defined as follows: Program a group of related entities (Java @Entity
classes), one-by-one, in a dedicated Maven module. Define in this Maven module also a composite persistence unit member (important!). The composite unit member PuPersonData refers to this set of related entities that characterizes person data. Define the member persistence unit PuPersonData as (
<persistence-unit name="PuPersonData" transaction-type="JTA">
...
<jta-data-source>jdbc/PostgresDs</jta-data-source>
...
).
In a second Maven module, define another composite persistence unit member, PuWebTraffic (
<persistence-unit name="PuWebTraffic" transaction-type="JTA">
...
<jta-data-source>jdbc/PostgresDs</jta-data-source>
...
). Include here other entities (Java classes denoted with @Entity
) that store data about web-transactions, logon, sessions, etc.
Needless to state, the two composite persistence unit members must be disjoint with respect to entities, no overlap is allowed in entity-names.
Both persistence unit members have in their XML-definitions the property:
<properties>
<property name="eclipselink.composite-unit.member" value="true"/>
...
</properties>
Composite persistence unit
We now define in a third Maven module the composite persistence unit CPuPersonSessionData that includes both the persistence units members PuPersonData and PuWebTraffic.
<persistence-unit name="CPuPersonSessionData" transaction-type="JTA">
This composite persistence unit CPuPersonSessionData refers to the two persistence unit members, PuPersonData and PuWebTraffic, by means of including the jars that result from compilation of the two pertaining Maven modules.
...
<jar-file>PuPersonData.jar</jar-file>
<jar-file>PuWebTraffic.jar</jar-file>
...
In the XML-definition of the composite persistence unit, the following property needs to be set
<properties>
<property name="eclipselink.composite-unit" value="true"/>
...
</properties>
This setting ensures that the composite persistence unit is treated differently by Java EE than its persistence unit members.
Use of persistence unit in Java
In the Java web-application that is going to store and retrieve entities with both person-data and traffic-data, only the composite persistence unit is included
@Stateless
public class DataLayer {
@PersistenceUnit(unitName="CPuPersonSessionData")
EntityManager em;
...
The normal 'em' operations such as persist
, find
and merge
can now be performed on each entity, contained in one of the composite entity members.
Under Payara, no XA-transactions were needed for this composite persistence unit to address the entities pertaining to each of the persistence unit members.
Maven
The Maven parent POM file needs to contain the specifications for the pertaining modules.
...
<modules>
<module>PersonData</module>
<module>WebTraffic</module>
<module>PersonSessionData</module>
</modules>
...
The POM-file of each module needs to be configured as a normal Maven-project, referring to the parent POM-file.
Pitfalls:
- You need to configure the Maven multi-module project correctly, which can be somewhat tricky. Each composite persistence unit member constitutes a separate Maven module. Also the composite persistence unit is a separate Maven module. The members need to be compiled first, in Maven sequence.
- The ‘jars’ in the composite persistence unit need to be found when compiling the module of the composite persistence unit.
- The entities of each composite persistence unit member need to be available in the resulting ‘jar’, directly in the ‘classes’ directory (adding extra paths to the entities, via Maven, is possible but complex).
- The ‘jars’ of the persistence unit members need to be available in the ‘classes’ directory for the composite persistence unit to find them.
The benefit gained is a neat Enterprise data-layer that works with reusable entities, each with one central definition. Moreover, it is possible to perform cross-unit native SQL-queries. I got this to work also.
Documentation states that cross-unit native queries will not work when the composite persistence unit members run on different, actual databases. This should still be verified.