JDO : PersistenceManagerFactory

Any JDO-enabled application will require at least one PersistenceManagerFactory (PMF). Typically applications create one per datastore being utilised. A PersistenceManagerFactory provides access to PersistenceManagers which allow objects to be persisted, and retrieved. The PersistenceManagerFactory can be configured to provide particular behaviour.

Important : A PersistenceManagerFactory is designed to be thread-safe. A PersistenceManager is not

There are many ways of creating a PersistenceManagerFactory .

Properties properties = new Properties();
properties.setProperty("javax.jdo.PersistenceManagerFactoryClass", 
    "org.datanucleus.api.jdo.JDOPersistenceManagerFactory");
properties.setProperty("javax.jdo.option.ConnectionURL","jdbc:mysql://localhost/myDB");
properties.setProperty("javax.jdo.option.ConnectionDriverName","com.mysql.jdbc.Driver");
properties.setProperty("javax.jdo.option.ConnectionUserName","login");
properties.setProperty("javax.jdo.option.ConnectionPassword","password");
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(properties);

A slight variation on this, is to have a file to specify these properties like this

javax.jdo.PersistenceManagerFactoryClass=org.datanucleus.api.jdo.JDOPersistenceManagerFactory
javax.jdo.option.ConnectionURL=jdbc:mysql://localhost/myDB
javax.jdo.option.ConnectionDriverName=com.mysql.jdbc.Driver
javax.jdo.option.ConnectionUserName=login
javax.jdo.option.ConnectionPassword=password

and then to create the PersistenceManagerFactory using this file

File propsFile = new File(filename);
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory(propsFile);

or if the above file is in the CLASSPATH (at "datanucleus.properties" in the root of the CLASSPATH), then

PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("datanucleus.properties");

If using a named PMF file, you can create the PMF by providing the name of the PMF like this

PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("myNamedPMF");

If using a META-INF/persistence.xml file, you can simply specify the persistence-unit name as

PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("myPersistenceUnit");

Another alternative, when specifying your datastore via JNDI, would be to call JDOHelper.getPersistenceManagerFactory(jndiLocation, context);, and then set the other persistence properties on the received PMF.

Whichever way we wish to obtain the PersistenceManagerFactory we have defined a series of properties to give the behaviour of the PersistenceManagerFactory. The first property specifies to use the DataNucleus implementation, and the following 4 properties define the datastore that it should connect to. There are many properties available. Some of these are standard JDO properties, and some are DataNucleus extensions.


Specifying the datastore properties

With JDO you have 3 ways of specifying the datastore via persistence properties

  • 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.jdo.option.ConnectionDriverName, javax.jdo.option.ConnectionURL, javax.jdo.option.ConnectionUserName, and javax.jdo.option.ConnectionPassword
  • Specify the JNDI name of the connectionFactory This is achieved by specifying javax.jdo.option.ConnectionFactoryName, and javax.jdo.option.ConnectionFactory2Name (for secondary operations)
  • Specify the DataSource of the connectionFactory This is achieved by specifying javax.jdo.option.ConnectionFactory, and javax.jdo.option.ConnectionFactory2 (for secondary operations)

JDO Persistence Properties

Name Values Description
javax.jdo.PersistenceManagerFactoryClass The name of the PMF implementation. org.datanucleus.api.jdo.JDOPersistenceManagerFactory Only required if you have more than one JDO implementation in the CLASSPATH
javax.jdo.option.ConnectionFactory Alias for datanucleus.ConnectionFactory
javax.jdo.option.ConnectionFactory2 Alias for datanucleus.ConnectionFactory2
javax.jdo.option.ConnectionFactoryName Alias for datanucleus.ConnectionFactoryName
javax.jdo.option.ConnectionFactory2Name Alias for datanucleus.ConnectionFactory2Name
javax.jdo.option.ConnectionDriverName Alias for datanucleus.ConnectionDriverName
javax.jdo.option.ConnectionURL Alias for datanucleus.ConnectionURL
javax.jdo.option.ConnectionUserName Alias for datanucleus.ConnectionUserName
javax.jdo.option.ConnectionPassword Alias for datanucleus.ConnectionPassword
javax.jdo.option.IgnoreCache true | false Alias for datanucleus.IgnoreCache
javax.jdo.option.Multithreaded true | false Alias for datanucleus.Multithreaded
javax.jdo.option.NontransactionalRead false | true Alias for datanucleus.NontransactionalRead
javax.jdo.option.NontransactionalWrite false | true Alias for datanucleus.NontransactionalWrite
javax.jdo.option.Optimistic true | false Alias for datanucleus.Optimistic
javax.jdo.option.RetainValues true | false Alias for datanucleus.RetainValues
javax.jdo.option.RestoreValues true | false Alias for datanucleus.RestoreValues
javax.jdo.option.Mapping Alias for datanucleus.Mapping RDBMS datastores only
javax.jdo.mapping.Catalog Alias for datanucleus.Catalog RDBMS datastores only
javax.jdo.mapping.Schema Alias for datanucleus.Schema RDBMS datastores only
javax.jdo.option.DetachAllOnCommit true | false Alias for datanucleus.DetachAllOnCommit
javax.jdo.option.TransactionType Alias for datanucleus.TransactionType
javax.jdo.option.PersistenceUnitName Alias for datanucleus.PersistenceUnitName
javax.jdo.option.ServerTimeZoneID Alias for datanucleus.ServerTimeZoneID
javax.jdo.option.Name Name of the named PMF to use. Refers to a PMF defined in "META-INF/jdoconfig.xml".
javax.jdo.option.CopyOnAttach true | false Alias for datanucleus.CopyOnAttach
javax.jdo.option.ReadOnly true | false Alias for datanucleus.readOnlyDatastore
javax.jdo.option.TransactionIsolationLevel Alias for datanucleus.transactionIsolation
javax.jdo.option.DatastoreReadTimeoutMillis Alias for datanucleus.datastoreReadTimeout
javax.jdo.option.DatastoreWriteTimeoutMillis Alias for datanucleus.datastoreWriteTimeout

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

PersistenceManagerFactory for 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. JDO uses the (JPA) 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 the CLASSPATH (this may mean WEB-INF/classes/META-INF when using a web-application). This file will be used to define your persistence-units. Lets 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">
        <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="datanucleus.ConnectionDriverName" value="org.h2.Driver"/>
            <property name="datanucleus.ConnectionURL" value="jdbc:h2:mem:datanucleus"/>
            <property name="datanucleus.ConnectionUserName" value="sa"/>
            <property name="datanucleus.ConnectionPassword" value=""/>
        </properties>
    </persistence-unit>

    <!-- Accounting -->
    <persistence-unit name="Accounting">
        <mapping-file>/com/datanucleus/samples/metadata/accounts/package.jdo</mapping-file>
        <properties>
            <property name="datanucleus.ConnectionDriverName" value="org.h2.Driver"/>
            <property name="datanucleus.ConnectionURL" value="jdbc:h2:mem:datanucleus"/>
            <property name="datanucleus.ConnectionUserName" value="sa"/>
            <property name="datanucleus.ConnectionPassword" 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 "package.jdo" 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 - Not used by JDO
  • jta-data-source - JNDI name for JTA connections
  • non-jta-data-source - JNDI name for non-JTA connections
  • 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. This is the "JDO" mapping file (not the ORM)
  • class - name of an annotated class to include in this persistence-unit
  • properties - properties defining the persistence factory to be used.

Use with JDO

JDO accepts the "persistence-unit" name to be specified when creating the PersistenceManagerFactory, like this

PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("MyPersistenceUnit");

Dynamically generated Persistence-Unit

DataNucleus allows an extension to JDO 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.jdo.JDOPersistenceManagerFactory;
 
PersistenceUnitMetaData pumd = new PersistenceUnitMetaData("dynamic-unit", "RESOURCE_LOCAL", null);
pumd.addClassName("org.datanucleus.test.A");
pumd.setExcludeUnlistedClasses();
pumd.addProperty("javax.jdo.ConnectionURL", "jdbc:hsqldb:mem:nucleus");
pumd.addProperty("javax.jdo.ConnectionDriverName", "org.hsqldb.jdbcDriver");
pumd.addProperty("javax.jdo.ConnectionUserName", "sa");
pumd.addProperty("javax.jdo.ConnectionPassword", "");
pumd.addProperty("datanucleus.autoCreateSchema", "true");

PersistenceManagerFactory pmf = new JDOPersistenceManagerFactory(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.

Named PersistenceManagerFactory

Typically applications create one PMF per datastore being utilised. An alternate to persistence-unit is to use a named PMF, defined in a file META-INF/jdoconfig.xml at the root of the CLASSPATH (this may mean WEB-INF/classes/META-INF when using a web-application). Let's see an example of a jdoconfig.xml

<?xml version="1.0" encoding="utf-8"?>
<jdoconfig xmlns="http://xmlns.jcp.org/xml/ns/jdo/jdoconfig"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://xmlns.jcp.org/xml/ns/jdo/jdoconfig">

    <!-- Datastore Txn PMF -->
    <persistence-manager-factory name="Datastore">
        <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
        <property name="javax.jdo.option.ConnectionURL" value="jdbc:mysql://localhost/datanucleus?useServerPrepStmts=false"/>
        <property name="javax.jdo.option.ConnectionDriverName" value="com.mysql.jdbc.Driver"/>
        <property name="javax.jdo.option.ConnectionUserName" value="datanucleus"/>
        <property name="javax.jdo.option.ConnectionPassword" value=""/>
        <property name="javax.jdo.option.Optimistic" value="false"/>
        <property name="datanucleus.autoCreateSchema" value="true"/>
    </persistence-manager-factory>

    <!-- Optimistic Txn PMF -->
    <persistence-manager-factory name="Optimistic">
        <property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
        <property name="javax.jdo.option.ConnectionURL" value="jdbc:mysql://localhost/datanucleus?useServerPrepStmts=false"/>
        <property name="javax.jdo.option.ConnectionDriverName" value="com.mysql.jdbc.Driver"/>
        <property name="javax.jdo.option.ConnectionUserName" value="datanucleus"/>
        <property name="javax.jdo.option.ConnectionPassword" value=""/>
        <property name="javax.jdo.option.Optimistic" value="true"/>
        <property name="datanucleus.autoCreateSchema" value="true"/>
    </persistence-manager-factory>

</jdoconfig>

So in this example we have 2 named PMFs. The first is known by the name "Datastore" and utilises datastore transactions. The second is known by the name "Optimistic" and utilises optimistic transactions. You simply define all properties for the particular PMF within its specification block. And finally we instantiate our PMF like this

PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("Optimistic");

That's it. The PMF we are returned from JDOHelper will have all of the properties defined in META-INF/jdoconfig.xml under the name of "Optimistic".