A common use case for an application running in a servlet or application server is to "detach" objects from all server resources, modify them, and then "attach" them again. For example, a servlet might store persistent data in a user session between a modification based on a series of web forms. Between each form request, the web container might decide to serialize the session, requiring that the stored persistent state be disassociated from any other resources. Similarly, a client/server application might transfer persistent objects to a client via serialization, allow the client to modify their state, and then have the client return the modified data in order to be saved. This is sometimes referred to as the data transfer object or value object pattern, and it allows fine-grained manipulation of data objects without incurring the overhead of multiple remote method invocations.
JDO provides support for this pattern using detach
APIs that allow you to detach a persistent instance. You can then
modify the detached instance offline, and attach the instance back
into a PersistenceManager
- either the same one
that detached the instance or a new one - using
makePersistent
, which applies the changes to
the the datastore.
In order to be able to detach a persistent instance, the
metadata for the class must declare that it is eligible for
detachment using the detachable
class attribute. We described this attribute in
Section 5.3, “Class Element”.
Note | |
---|---|
After changing the |
public Object detachCopy (Object pc); public Collection detachCopyAll (Collection pcs); public Object[] detachCopyAll (Object[] pcs);
Each detach method returns unmanaged copies of the given instances. The copy mechanism is similar to serialization, except that only currently-loaded fields are copied.
When serializing a detachable object, the serialized copy will be in the detached state automatically. You do not need to explicitly detach an object before serializing it.
Whether through detachCopy
or through
serialization, detaching a dirty instance causes
the current transaction transaction to flush. This means that when
subsequently re-attaching the detached object, JDO assumes that the
transaction from which it was originally detached committed. If
the transaction rolled back, then either the re-attachment process will
throw an exception, or the transaction in which you re-attach the
instance will fail on commit, just as if a normal optimistic conflict
was detected.
public boolean getDetachAllOnCommit (); public void setDetachAllOnCommit (boolean detach);
Set the DetachAllOnCommit
property to automatically
detach the entire PersistenceManager
cache on
commit. Unlike the explicit detachCopy
methods, the implicit detach-on-commit occurs in-place. Every instance
in the PersistenceManager
cache transitions to
the detached state, then the cache is cleared.
Note | |
---|---|
Kodo offers many enhancements to JDO detachment functionality, including additional options for automatic detachment. See Section 11.1, “Detach and Attach” in the Reference Guide for details. |
Example 8.4. Detaching and Attaching
This example demonstrates a common client/server scenario. The client requests objects and makes changes to them, while the server handles the object lookups and transactions.
// CLIENT: // requests an object with a given oid Record detached = (Record) getFromServer (oid); ... // SERVER: // detaches object and returns to client Object oid = processClientRequest (); PersistenceManager pm = pmf.getPersistenceManager (); Record record = (Record) pm.getObjectById (oid); // we detach explicitly because we want to close the PM before serializing Record detached = (Record) pm.detachCopy (record); pm.close (); sendToClient (detached); ... // CLIENT: // makes some modifications and sends back to server detached.setSomeField ("bar"); sendToServer (detached); ... // SERVER: // re-attaches the instance and commit the changes Record modified = (Record) processClientRequest (); PersistenceManager pm = pmf.getPersistenceManager (); pm.currentTransaction ().begin (); Record attached = (Record) pm.makePersistent (modified); attached.setLastModified (System.currentTimeMillis ()); attached.setModifier (getClientIdentityCode ()); pm.currentTransaction ().commit (); pm.close ();