Clearly java persistence is complex and there are many ways of utilising it in your application.
This section attempts to give a few pointers that you may find useful in avoiding issues.
This guide should be read in conjunction with the Performance Tuning Guide.
There should be 3 steps in your use of JPOX.
- Deciding which classes to persist and how to persist them to the datastore
- Creating the schema or validating that it matches the persistence decisions taken in step 1.
This step is for datastores that have a schema (i.e RDBMS) and is not needed for DB4O.
- Running your application
Many people like to perform steps 2 and 3 together because JPOX will support the creation of schemas dynamically.
This can, however, confuse issues where the MetaData is incompatible with the existing schema for example,
or where the MetaData definition is incorrectly specified. When using an RDBMS datastore it is always best to
use JPOX SchemaTool to either create the schema (where you are creating a new schema) or to validate it
(where you are using an existing schema).
This means that you isolate issues about the schema and MetaData before running your application.
Once you have isolated all issues around the schema and the MetaData you can then run your application. Since
you know that the schema exists and is valid for your MetaData you can safely run with the properties
org.jpox.autoCreateSchema, org.jpox.autoCreateTables, org.jpox.autoCreateColumns,
org.jpox.autoCreateConstraints, org.jpox.validateTables, and org.jpox.validateConstraints
all set to false. This will lead to much better performance for your application since fewer checks will
be made at runtime of the schema structure.
Creation of PersistenceManagerFactory and EntityManagerFactory
objects can be expensive and should be kept to a minimum. Depending on the structure of your application,
use a single persistence factory per datastore wherever possible.
Clearly if your application spans multiple servers then this may be impractical, but should be borne in mind.
Clearly the structure of your application will have a major influence on how you utilise a
PersistenceManager or EntityManager.
A pattern that gives a clean definition of process is to use a different persistence manager for each request to the
data access layer. This reduces the risk of conflicts where one thread performs an operation and this impacts on
the successful completion of an operation being performed by another thread. Creation of PersistenceManager's is
not an expensive process and use of multiple threads writing to the same persistence manager should be avoided.
When you need to use objects in a different layer of your application (outside of the datastore layer) you need
a mechanism for taking the objects in a form where they can be used. JDO2 provides detach/attach functionality
for this purpose. There are two ways of detaching objects. The first is to use PersistenceManager.detachCopy()
however this can be computationally expensive since it has to create copies of the objects (and also down an object
graph too if required). The second way is to use the PMF property javax.jdo.option.DetachAllOnCommit which means
that the existing objects that have been enlisted in the current transaction are automatically migrated into
detached state. This is not computationally expensive and means that you can now use your objects and update
them directly before sending them back to the datastore layer for persisting.
... (create PMF with javax.jdo.option.DetachAllOnCommit set to true)
// Datastore Tier - persist any new objects
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try
{
tx.begin();
pm.makePersistent(myObj);
tx.commit();
// myObj is now detached
}
finally
{
if (tx.isActive())
{
tx.rollback();
}
}
// Business Tier - update your objects
... update "myObj" in your business layer
// Datastore Tier - persist any changes to your objects
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try
{
tx.begin();
// Attach the updated (detached) myObj
pm.makePersistent(myObj);
tx.commit();
// myObj is now detached again for any further updates
}
finally
{
if (tx.isActive())
{
tx.rollback();
}
}
So the move to "detached" state is transparent and you can use your objects directly when they leave the
datastore tier.