13.4 Making a Persistent Instance Transient
Suppose you have a persistent instance that you want to make
accessible to a client application via Remote Method Invocation
(RMI). Suppose your code is executing in a Common Object Request Broker
Architecture (CORBA) or application-server environment, where the
transaction context will no longer exist once your servlet or session
bean returns from a client invocation. When RMI serializes your
instance, the transaction is no longer active. You do not want the
PersistenceManager to mediate access to a
persistent instance outside of a transaction context. So, to pass the
persistent instance to a remote client, you must convert it into a
transient instance. This is necessary to disassociate the instance
with the PersistenceManager, so field access is
not mediated.
You do this by making the persistent instance transient. You can use
the following PersistenceManager methods to make
persistent instances transient:
void makeTransient(Object obj);
void makeTransientAll(Object[] objs);
void makeTransientAll(Collection objs);
When the instances transition to transient, they lose their identity
and association with the PersistenceManager. They
are no longer associated with their representation in the datastore,
so their in-memory state does not affect the persistent state in the
datastore. Even though the instance in memory is transient, the
instance still exists in the datastore. Making a persistent instance
transient is not equivalent to calling deletePersistent(
). The effect of these methods is immediate and permanent;
if a transaction rollback occurs, the instances remain transient. If
a parameter is already transient, these methods have no effect.
A persistent-dirty instance has changes to field values that are not
committed to the datastore until transaction commit. You do not want
to lose these changes, which occurs when an instance is disassociated
with its PersistenceManager. Therefore, if you
pass a persistent-dirty instance to these methods, a
JDOUserException
is thrown.
Before calling makeTransient( ), you should call
retrieve(
) or
retrieveAll(
) to fetch all the field's values from the
datastore. Otherwise, some of the fields may not be fetched. The
makeTransient( ) methods do not change the values
of the fields in the parameter instances.
Another use for makeTransient( ) is to copy an
instance from one transaction to another that is running in the same
JVM. The following code copies a persistent instance from one
PersistenceManager instance
(pm1) to another (pm2):
RentalCodeKey key = new RentalCodeKey("High Demand");
RentalCode code = (RentalCode) pm1.getObjectById(key, true);
pm1.retrieve(code);
pm1.makeTransient(code);
pm2.makePersistent(code);
The PersistenceManager referenced by
pm2 might be from the same JDO implementation as
pm1 but a different datastore. Or,
pm1 and pm2 could be from
different JDO implementations and datastores.
If you want the instances to remain transient at transaction commit,
you must make sure that all references to them from other persistent
instances in memory are changed; you should also make the referring
persistent instances transient. Otherwise, the
persistence-by-reachability
algorithm will cause the instances to become persistent again at
commit. Since the original persistent instance still exists in the
datastore, if the instance becomes persistent again as a result of
persistence-by-reachability, there might be two copies of the
instance in the datastore. If the class uses datastore identity, the
new transient instance is assigned a new identity value. However, if
the class uses application identity and you did not change the value
of the primary key, you get an exception indicating that you have a
duplicate primary-key value.
|