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.
With JDO you have 3 ways of specifying the datastore via 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 | true | false | Alias for datanucleus.NontransactionalRead |
javax.jdo.option.NontransactionalWrite | true | false | 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.DetachAllOnCommit | true | false | Alias for datanucleus.DetachAllOnCommit |
javax.jdo.option.CopyOnAttach | true | false | Alias for datanucleus.CopyOnAttach |
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.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 | |
javax.jdo.option.Mapping | Alias for datanucleus.Mapping Only for datastores with a "schema" | |
javax.jdo.mapping.Catalog | Alias for datanucleus.Catalog Only for datastores with a "schema" | |
javax.jdo.mapping.Schema | Alias for datanucleus.Schema Only for datastores with a "schema" |
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.
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 in such as Tomcat). 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
JDO accepts the "persistence-unit" name to be specified when creating the PersistenceManagerFactory, like this
PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("MyPersistenceUnit");
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.schema.autoCreateAll", "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.
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.schema.autoCreateAll" 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.schema.autoCreateAll" 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".