8.7. Detach and Attach Functionality

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 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]Note

After changing the detachable attribute of a class, you must re-enhance it. Detachability requires that the enhancer add additional fields to the class to hold information about the persistent instance's identity and state.

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]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 ();

 

Skip navigation bar   Back to Top