JPA : Entity Manager Factory

Any JPA-enabled application will require at least one EntityManagerFactory. Typically applications create one per datastore being utilised. An EntityManagerFactory provides access to EntityManagers which allow objects to be persisted, and retrieved. The EntityManagerFactory can be configured to provide particular behaviour.

Important : an EntityManagerFactory is designed to be thread-safe. An EntityManager is not

Create an EMF in JavaSE

The simplest way of creating an EntityManagerFactory in a JavaSE environment is as follows

import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

...

EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU");

So you simply provide the name of the persistence-unit which defines the properties, classes, meta-data etc to be used. An alternative is to specify the properties to use along with the persistence-unit name. In that case the passed properties will override any that are specified for the persistence unit itself.

EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPU", overridingProps);

Create an EMF in JavaEE

If you want an application-managed EMF then you create it by injection like this, providing the name of the required persistence-unit

@PersistenceUnit(unitName="myPU")
EntityManagerFactory emf;

If you want a container-managed EM then you create it by injection like this, providing the name of the required persistence-unit

@PersistenceContext(unitName="myPU")
EntityManager em;

Please refer to the docs for your JavaEE server for more details.

Persistence Unit

When designing an application you can usually nicely separate your persistable objects into independent groupings that can be treated separately, perhaps within a different DAO object, if using DAOs. JPA introduces the idea of a persistence-unit. A persistence-unit provides a convenient way of specifying a set of metadata files, and classes, and jars that contain all classes to be persisted in a grouping. The persistence-unit is named, and the name is used for identifying it. Consequently this name can then be used when defining what classes are to be enhanced, for example.

To define a persistence-unit you first need to add a file persistence.xml to the META-INF/ directory of your application jar. This file will be used to define your persistence-units. Let's show an example

<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd" version="2.1">

    <!-- Online Store -->
    <persistence-unit name="OnlineStore">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
        <class>org.datanucleus.samples.metadata.store.Product</class>
        <class>org.datanucleus.samples.metadata.store.Book</class>
        <class>org.datanucleus.samples.metadata.store.CompactDisc</class>
        <class>org.datanucleus.samples.metadata.store.Customer</class>
        <class>org.datanucleus.samples.metadata.store.Supplier</class>
        <exclude-unlisted-classes/>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:datanucleus"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>
        </properties>
    </persistence-unit>

    <!-- Accounting -->
    <persistence-unit name="Accounting">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
        <mapping-file>com/datanucleus/samples/metadata/accounts/orm.xml</mapping-file>
        <properties>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:datanucleus"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.user" value="sa"/>
            <property name="javax.persistence.jdbc.password" value=""/>
        </properties>
    </persistence-unit>

</persistence>

In this example we have defined 2 persistence-units. The first has the name "OnlineStore" and contains 5 classes (annotated). The second has the name "Accounting" and contains a metadata file called "orm.xml" in a particular package (which will define the classes being part of that unit). This means that once we have defined this we can reference these persistence-units in our persistence operations. You can find the XSD for persistence.xml here.

There are several sub-elements of this persistence.xml file

  • provider - the JPA persistence provider to be used. The JPA persistence "provider" for DataNucleus is org.datanucleus.api.jpa.PersistenceProviderImpl
  • jta-data-source - JNDI name for JTA connections
  • non-jta-data-source - JNDI name for non-JTA connections. Note that if using a JTA datasource as the primary connection, you ought to provide a non-jta-data-source also since any schema generation and/or sequence handling will need to use that.
  • jar-file - name of a JAR file to scan for annotated classes to include in this persistence-unit.
  • mapping-file - name of an XML "mapping" file containing persistence information to be included in this persistence-unit.
  • class - name of an annotated class to include in this persistence-unit
  • properties - properties defining the persistence factory to be used. Please refer to Persistence Properties Guide for details

Specifying the datastore properties

With a persistence-unit you have 2 ways of specifying the datastore to use

  • Specify the connection URL/driverName/userName/password and it will internally create a DataSource for this URL (with optional connection pooling). This is achieved by specifying javax.persistence.jdbc.url, javax.persistence.jdbc.driver, javax.persistence.jdbc.user, and javax.persistence.jdbc.password properties
  • Specify the JNDI name of the connectionFactory This is achieved by specifying javax.persistence.jtaDataSource, and javax.persistence.nonJtaDataSource (for secondary operations) or by specifying the element(s) jta-data-source/non-jta-data-source

Restricting to specific classes

If you want to just have specific classes in the persistence-unit you can specify them using the class element, and then add exclude-unlisted-classes, like this

    <persistence-unit name="Store">
        <provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
        <class>org.datanucleus.samples.metadata.store.Product</class>
        <class>org.datanucleus.samples.metadata.store.Book</class>
        <class>org.datanucleus.samples.metadata.store.CompactDisc</class>
        <exclude-unlisted-classes/>
        ...
    </persistence-unit>

If you don't include the exclude-unlisted-classes then DataNucleus will search for annotated classes starting at the root of the persistence-unit (the root directory in the CLASSPATH that contains the "META-INF/persistence.xml" file).

Dynamically generated Persistence-Unit

DataNucleus allows an extension to JPA to dynamically create persistence-units at runtime. Use the following code sample as a guide. Obviously any classes defined in the persistence-unit need to have been enhanced.

import org.datanucleus.metadata.PersistenceUnitMetaData;
import org.datanucleus.api.jpa.JPAEntityManagerFactory;
 
PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("org.datanucleus.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.persistence.jdbc.url", "jdbc:h2:mem:nucleus");
pumd.addProperty("javax.persistence.jdbc.driver", "org.h2.Driver");
pumd.addProperty("javax.persistence.jdbc.user", "sa");
pumd.addProperty("javax.persistence.jdbc.password", "");
pumd.addProperty("datanucleus.schema.autoCreateAll", "true");

EntityManagerFactory emf = new JPAEntityManagerFactory(pumd, null);

It should be noted that if you call pumd.toString(); then this returns the text that would have been found in a persistence.xml file.

Standard JPA Properties

Parameter Values Description
javax.persistence.provider Class name of the provider to use. DataNucleus has a provider name of org.datanucleus.api.jpa.PersistenceProviderImpl If you only have 1 persistence provider in the CLASSPATH then this doesn't need specifying.
javax.persistence.transactionType RESOURCE_LOCAL | JTA Type of transactions to use. In Java SE the default is RESOURCE_LOCAL. In Java EE the default is JTA. Note that if using a JTA datasource as the primary connection, you ought to provide a non-jta-data-source also since any schema generation and/or sequence handling will need to use that.
javax.persistence.jtaDataSource JNDI name of a (transactional) JTA data source. Note that if using a JTA datasource as the primary connection, you ought to provide a non-jta-data-source also since any schema generation and/or sequence handling will need to use that.
javax.persistence.nonJtaDataSource JNDI name of a (non-transactional) data source.
javax.persistence.jdbc.url Alias for datanucleus.ConnectionURL. Note that this is (also) used to define which type of datastore is being used
javax.persistence.jdbc.driver Alias for datanucleus.ConnectionDriverName
javax.persistence.jdbc.user Alias for datanucleus.ConnectionUserName
javax.persistence.jdbc.password Alias for datanucleus.ConnectionPassword
javax.persistence.query.timeout Alias for datanucleus.query.timeout
javax.persistence.sharedCache.mode Alias for datanucleus.cache.level2.mode
javax.persistence.validation.mode Alias for datanucleus.validation.mode
javax.persistence.validation.group.pre-persist Alias for datanucleus.validation.group.pre-persist
javax.persistence.validation.group.pre-update Alias for datanucleus.validation.group.pre-update
javax.persistence.validation.group.pre-remove Alias for datanucleus.validation.group.pre-remove
javax.persistence.validation.factory Alias for datanucleus.validation.factory
javax.persistence.schema-generation.database.action create | drop | drop-and-create | none Alias for datanucleus.generateSchema.database.mode
javax.persistence.schema-generation.scripts.action create | drop | drop-and-create | none Alias for datanucleus.generateSchema.scripts.mode
javax.persistence.schema-generation.scripts.create-target {filename} Alias for datanucleus.generateSchema.scripts.create.target
javax.persistence.schema-generation.scripts.drop-target {filename} Alias for datanucleus.generateSchema.scripts.drop.target
javax.persistence.schema-generation.create-script-source {filename} Alias for datanucleus.generateSchema.scripts.create.source
javax.persistence.schema-generation.drop-script-source {filename} Alias for datanucleus.generateSchema.scripts.drop.source
javax.persistence.sql-load-script-source {filename} Alias for datanucleus.generateSchema.scripts.load. Note that all versions up to and including 4.0.0.m2 used javax.persistence.sql.load-script-source as the property name

Extension DataNucleus Properties

DataNucleus provides many properties to extend the control that JPA gives you. These can be used alongside the above standard JPA properties, but will only work with DataNucleus. Please consult the Persistence Properties Guide for full details. In addition we have the following properties explicitly for JPA.


datanucleus.jpa.addClassTransformer
Description When running with JPA in a JavaEE environment if you wish to have your classes enhanced at runtime you can enable this by setting this property to true. The default is to bytecode enhance your classes before deployment.
Range of Values false | true

datanucleus.jpa.persistenceContextType
Description JPA defines two lifecycle options. JavaEE usage defaults to "transaction" where objects are detached when a transaction is committed. JavaSE usage defaults to "extended" where objects are detached when the EntityManager is closed. This property allows control
Range of Values transaction | extended

datanucleus.jpa.txnMarkForRollbackOnException
Description JPA requires that any persistence exception should mark the current transaction for rollback. This persistence property allows that inflexible behaviour to be turned off leaving it to the user to decide when a transaction is needing to be rolled back.
Range of Values true | false