Controlling JDO s Management of Data Objects


Controlling JDO's Management of Data Objects

As Figure 3-1 shows, the persistence manager has a group of ten operations that control how JDO directly manages application data objects and indirectly manages the embedded objects that the application data objects refer to. These operations, when they have any effect, immediately modify the management state of the application data object.

The Behavior of the xxxAll Operations

There are five operations in this group that end in "All". Each of them, as indicated by the plus sign next to their entry in Figure 3-1, has more than one method signature. Some methods take a Collection of application data objects, and some take an array of application data objects. The behavior of the xxxAll operation, where xxx is makePersistent, deletePersistent, and so on, derives from the behavior of the corresponding xxx operation and two simple rules:

  • The xxxAll methods perform the xxx operation on each of the elements of the collection or array.

  • When the xxx operation is performed on one of the elements of the collection or array and an exception is thrown, this exception is collected and nested within a JDOUserException that is thrown when the xxxAll method has completed work on every element of the collection or array. Each nested JDOUserException contains a reference to the object that gave rise to that exception.

Consequently, the failure of the xxx operation on one or more elements of a collection or array does not prevent success with the other elements of the collection or array. Chapter 7 describes the exception types of JDO.

Making and Deleting Persistent Objects

The two operations makePersistent and deletePersistent add and delete objects from the datastore. The makePersistent operation turns a transient application data object into a persistent-new object and causes a later insertion of the object's persistent state into the datastore. The deletePersistent operation makes a persistent application data object persistent-deleted and causes a later deletion of the corresponding existing persistent state from the datastore. JDO is free to perform the insertion or deletion of the persistent state when it chooses, but it cannot commit the changes to the datastore until the JDO transaction commits. When the application calls makePersistent or deletePersistent, the persistence manager's transaction must be active; otherwise, a JDOUserException is thrown.

Making Transient Objects Persistent

The PersistenceManager interface provides three methods to make transient objects persistent.

 public void makePersistent(Object adObject) public void makePersistentAll(Collection adObjects) public void makePersistentAll(Object[] adObjects) 

The makePersistent methods always link the transient application data object to a new object state in the datastore. JDO does not provide a way for the application to say, "Here is a transient object, connect it to a preexisting object state in the database." To apply changes held in a transient object to a preexisting persistent state, the application must find the persistent object that refers to this state and then apply to the persistent object the updates indicated by the state of the transient object.

Note

Given an unmanaged application data object, an application can find the corresponding existing persistent state by using the object's durable JDO identity. If the application data class uses application identity, and if it requires that all application data objects of this class be constructed with valid key fields, then the application can construct the application identity object using the values of the key fields. If the application data class uses datastore identity, then the application must capture the identity object or its identity string before the application data object becomes unmanaged. See the section "Capturing the Identity String" in Chapter 7 for more details.

When the object is made persistent, a new JDO identity object is created for it. If the object uses datastore JDO identity, then JDO creates the identity value for it. If the object uses application identity, then the identity value is pulled from the key fields of the application data object. If there is another application data object in the persistence manager's cache with an equivalent JDO identity, then makePersistent throws a JDOUserException. Otherwise, if an object already exists in the datastore with the same identity value, then the datastore insert throws a JDOUserException upon transaction commit. The JDO implementation is responsible for avoiding duplicate use of datastore identity values, while the application is responsible for avoiding duplicate use of application identity values. In most cases, JDO configures the datastore to require unique identity values.

Note

The key fields of application identity are contained in the application data class and in the application identity class. See Chapter 1 for a fuller discussion of application identity. See Chapter 5 for a discussion of the JDO metadata.

If the application data object is in any of the following three transient states when it is passed to the makePersistent method, it becomes persistent-new:

  • JDO-transient

  • Transient-clean

  • Transient-dirty

When an object becomes persistent-new, JDO may save a before-image of the object for use in the event of rollback. The before-image contains the in-memory state of all managed fields. The RestoreValues property in the Transaction interface determines whether JDO saves the before-image and restores it in the event of rollback. In the case of objects that were transient-dirty, JDO will have already saved a before-image when the object became dirty, if RestoreValues is true. Otherwise, JDO saves the current state of the transient object when it becomes persistent-new, if RestoreValues is true. Chapter 4 describes the Transaction interface and its properties.

Passing an application data object in any of the seven persistent states to the makePersistent methods is a no-op for that object.

After makePersistent is called, the transient application data object becomes persistent-new. At the same time, JDO's persistence-by-reachability algorithm executes and makes persistent-new all transient application data objects that are reachable from the newly made persistent object. The state change for reachable objects is provisional. When the transaction commits, the reachability algorithm executes again, and any provisionally persistent-new application data objects that are not reachable revert to JDO-transient. Upon transaction commit, the persistent-new object's state is inserted into the database, and the object remains persistent but nontransactional. If the transaction is rolled back, the object management state reverts to JDO-transient, and when RestoreValues is true, the object is restored to the state saved in its before-image.

Note

Persistence by reachability, as explained in Chapter 1, is one of the elements of JDO's transparent persistence. To determine the objects that it can reach, JDO traverses the object graph starting with a root persistent object and tracing all of the data objects that can be found by following the persistent fields that have references. Implementations can be expected to optimize the reachability algorithm so that the tracing is not done by brute force.

When a data object is made persistent, either because it is explicitly passed to the makePersistent method or because it is made persistent implicitly as a result of persistence by reachability, JDO replaces the objects referred to by persistent fields of the supported mutable system types, such as Date and HashSet, with the implementation-supplied subclasses that support change tracking. The new objects are equivalent in value.

Deleting Persistent Objects

The PersistenceManagerInterface provides three methods to delete persistent application data objects.

 public void deletePersistent(Object adObject) public void deletePersistentAll(Collection adObjects) public void deletePersistentAll(Object[] adObjects) 

The deletePersistent operation either causes a preexisting persistent object to be removed from the datastore or prevents a newly made persistent object from being inserted into the datastore. After the call to deletePersistent, the persistent application data object is still persistent and in one of two management states, persistent-new-deleted or persistent-deleted. After the call to deletePersistent, the application can still read the primary key fields of the application data object, if it uses application identity, but any access to managed, non-key fields throws a JDOUserException.

When the transaction commits, the preexisting persistent state of a persistent-deleted object is removed from the datastore. Since there is no preexisting persistent state for a persistent-new-deleted object, there is nothing to remove from the datastore. After the transaction commits, the deleted application data object becomes JDO-transient.

When an application data object is deleted, any embedded objects that it refers to are also deleted. In general, JDO does not automatically delete the application data objects that the deleted object refers to. JDO does not specify deletion by reachability. JDO implementations may provide a way to define a cascading delete, but no such behavior is specified by JDO. Applications themselves can provide cascading deletes by implementing further delete operations in the jdoPreDelete callback method. See the discussion in "The InstanceCallbacks Interface" in Chapter 7 for more information.

If the transaction is rolled back, a persistent-new-deleted object becomes transient, and a persistent-deleted object becomes either hollow or persistent-nontransactional, depending on the value of the transaction's RestoreValues property. This property is discussed in Chapter 4.

The deletePersistent method works only on persistent objects. Passing transient or unmanaged objects to the method causes it to throw a JDOUserException.

Adding Objects to and Removing Them from Transactions

The two operations makeTransactional and makeNontransactional add and remove application data objects from the current transaction. As a general rule, JDO's transparent persistence implicitly makes objects transactional when they are read or modified and makes them nontransactional when the transaction ends. As a result, the application needs the makeTransactional and makeNontransactional operations only in special cases.

One case where these two methods are useful is to force a check of the concurrency value for persistent objects that are read, but not modified, within an optimistic transaction. Within an optimistic transaction, reading a managed field does not make the object transactional, as it does in a datastore transaction. When the optimistic transaction commits, the concurrency values of all transactional objects are checked against the value in the datastore. To force JDO to check the concurrency value of persistent objects that the application has not modified, the application must call makeTransactional to make the unmodified objects persistent-clean and therefore transactional. Within an optimistic transaction, this change does not refresh the persistent state of the affected object. The makeNontransactional method allows the application to make the persistent-clean object persistent-nontransactional again and thereby remove it from the concurrency value check at transaction commit.

Note

Chapter 4 describes the two types of transactions within JDO, optimistic and datastore. JDO does not specify how to implement optimistic transactions. Implementations might choose version numbers, timestamps, or some other technique.

The second case where the makeTransactional and makeNontransactional methods are useful is to permit the use of transient and transactional application data objects. Those JDO implementations that support the javax.jdo.option.TransientTransactional implementation option support two transient and transactional management states, transient-clean and transient-dirty. Both are transactional states. As a result of this optional feature, when the transient-clean application data object becomes dirty and the transaction's RestoreValues property is turned on, JDO saves for rollback the before-image of its managed fields. When the transaction commits, JDO discards any saved before-image. The values of fields in transient-clean and transient-dirty objects are never modified as the result of a commit, and of course, no persistent state is changed in the datastore. Practical uses for transient and transactional application data objects are likely to be highly specialized.

Making Objects Transactional

The PersistenceManager interface provides three methods to make nontransactional objects transactional.

 public void makeTransactional(Object adObject) public void makeTransactionalAll(Collection adObjects) public void makeTransactionalAll(Object[] adObjects) 

When successful, these methods associate the application data objects with the persistence manager's transaction. Seven of the ten JDO management states are transactional. Passing a transactional object to the makeTransactional operation is a no-op for that object.

Passing either a hollow or persistent-nontransactional object to makeTransactional succeeds only when the transaction is active. If the transaction is not active, the call throws a JDOUserException. When successful, the affected objects become persistent-clean.

Note

In JDO, each PersistenceManager object is associated with one Transaction object. The transaction may be active or inactive. Chapter 4 describes the Transaction interface.

In a datastore transaction, it is not necessary to call makeTransactional for either a hollow or a persistent-nontransactional object, since any read of a managed, non-key field makes the object persistent-clean. Passing a hollow or persistent-nontransactional object to makeTransactional also causes the object to become persistent-clean. If it was persistent-nontransactional before the call, its persistent state in memory is discarded. Fresh values for persistent fields are loaded from the datastore when needed.

In an optimistic transaction, JDO does not make a hollow or persistent-nontransactional object persistent-clean when a persistent field is read. Instead, JDO makes the object persistent-nontransactional, if it isn't already so. In an optimistic transaction, the call to makeTransactional forces the object, whether hollow or persistent-nontransactional, to become persistent-clean. In the case of persistent-nontransactional objects, the change to persistent-clean does not discard the persistent state in memory. In an optimistic transaction, persistent state is never discarded unless the application invokes refresh or evict to do so, or unless the transaction has been configured through the RetainValues and RestoreValues properties to do so at transaction completion. A value for a persistent field is loaded from the datastore only when it is not already cached in memory. Later, when the transaction commits, the concurrency values of all transactional objects are checked against the corresponding values in the datastore.

When the application data object passed to makeTransactional is JDO-transient and the implementation supports the two transient and transactional management states, then the call to makeTransactional succeeds whether a transaction is active or not. When a transaction is not active, the object remains in the transient-clean state even when its managed state is changed. Once a transaction becomes active, the transient-clean state changes to transient-dirty when a managed field is changed.

Making Transactional Objects Nontransactional

The PersistenceManager interface provides three methods to make transactional objects nontransactional.

 public void makeNontransactional(Object adObject) public void makeNontransactionalAll(Collection adObjects) public void makeNontransactionalAll(Object[] adObjects) 

These methods undo the action of the makeTransactional methods. In other words, they disassociate the objects from the persistence manager's transaction. For example, passing a persistent-clean object to the makeNontransactional method, when an optimistic transaction is active, causes the object to become persistent-nontransactional again. As a consequence, its concurrency value is not checked during transaction commit. Likewise, passing a transient-clean object to the makeNontransactional operation returns the object to a JDO-transient state. As a consequence, the object no longer interacts with transactions.

Passing a persistent-clean object to the makeNontransactional operation within a datastore transaction makes the object persistent-nontransactional, with one notable exception. If the JDO implementation does not support the NontransactionalRead implementation option, the call to makeNontransactional throws a JDOUnsupportedOptionException. Although the persistent-clean object becomes persistent-nontransactional, JDO may continue to hold locks on the persistent state in the datastore until the transaction ends.

Note

JDO specifies many optional features for JDO implementations. The features that an implementation supports can be determined from the string returned from the supportedOptions method in the PersistenceManagerFactory interface. Chapter 6 describes this interface and the various options.

Five of the JDO states are transactional and dirty states:

  • Persistent-new

  • Persistent-new-deleted

  • Persistent-deleted

  • Persistent-dirty

  • Transient-dirty

The makeNontransactional methods throw a JDOUserException when passed an object in one of the dirty states. It also throws a JDOUserException when the passed object is JDO-transient.

If the application data object passed to the makeNontransactional methods is in either the hollow or persistent-nontransactional state, then the call is a no-op for that object.

Removing Persistent Objects from JDO's Management

The PersistenceManager interface provides three methods to remove persistent application data objects from JDO's management.

 public void makeTransient(Object adObject) public void makeTransientAll(Collection adObjects) public void makeTransientAll(Object[] adObjects) 

These methods disconnect a persistent application data object from JDO's management and put it into the JDO-transient management state. They affect only the object in memory. They do not affect the persistent state in the datastore. The application can use a durable JDO identity or a query to find the persistent state in the datastore again. When this happens, JDO constructs another persistent object in memory.

Making a persistent object JDO-transient is a one-way operation. There is no equivalent reverse operation because there is no way to wire up a transient object in memory to a preexisting state in the datastore.

These methods have a few gotchas. To begin with, if another persistent and transactional object refers, by means of a persistent field, to the newly made transient object, then persistence by reachability makes the transient object persistent again when the transaction commits. This action is probably not what the application intends, since the implicit makePersistent action attempts to insert a new object state into the datastore. The solution for the application is to make transient all persistent objects that refer to the newly made transient object. Another solution is to change the references in the persistent objects so that they no longer refer to the newly made transient object.

Likewise, when a persistent object is made JDO-transient, any of its persistent fields may still hold references to other persistent objects. The call to makeTransient for an application data object does not make the objects that it refers to JDO-transient as well. When the application finds it necessary to prevent the newly made JDO-transient object from referring to persistent objects, the application must either change the references or make the objects referred to transient as well.

As mentioned earlier, the makeTransient methods do not affect the state stored in the datastore. As a consequence, making a persistent object JDO-transient when it lives in the middle of an object graph of persistent references may introduce some unexpected and unpredictable behavior in relationships. Consider the following example. Objects A and B are instances of the Person class, which has a persistent field dog that refers to an object of the Dog class. Suppose that persons A and B both own the same dog D and that the states of these three objects are stored in the datastore. The application finds person A and gets a reference to the dog D through A. The application next makes the dog D transient. Now the application finds person B and gets a reference to the dog through B. Does the reference obtained from A refer to the same object in memory as the reference obtained from B? The answer depends on what objects and references were cached prior to these actions. If the application data objects A, B, and D were all in the cache, and if the two references to D were cached, then both A and B refer to the same now JDO-transient dog D. If B was not in the cache or if its reference to D was not cached, then A refers to D, a JDO-transient Dog object, while B refers to a different and persistent Dog object.

The makeTransient methods are abrupt. They do not invoke transparent persistence, and they do not alter the values of any of the object's fields. In particular, they do not load persistent values in persistent fields. If the application data object is in a hollow state, then the newly made JDO-transient object has Java default values for all persistent fields. To load the persistent values before making the object JDO-transient, the application should call the retrieve operation, which is described later in this chapter.

The makeTransient methods change the passed object to JDO-transient when the object is in one of the following three management states:

  • Persistent-clean

  • Hollow

  • Persistent-nontransactional

The change is not subject to rollback. The makeTransient methods make persistent-nontransactional and hollow objects unmanaged whether or not a transaction is active.

The makeTransient methods perform no operation on passed objects in any of the following three management states:

  • Transient

  • Transient-clean

  • Transient-dirty

The makeTransient methods throw a JDOUserException when the passed object is in any of the remaining four management states:

  • Persistent-new

  • Persistent-new-deleted

  • Persistent-deleted

  • Persistent-dirty

Alternatives to Calling the makeTransient Methods

The application can obtain a JDO-transient application data object in any of four ways: by construction, by cloning, by serialization, and by calling one of the makeTransient methods.

When the application constructs an application data object, the newly constructed object does not represent any persistent state in the datastore.

If the application obtains a transient object by cloning, the call to super.clone() to obtain the clone is, like the call to the makeTransient operation, abrupt. In other words, it won't invoke transparent persistence to load persistent fields. Unlike makeTransient, cloning does not affect the original application data object. Because the clone method returns a copy, two of the problems that using makeTransient can cause are avoided. There is no danger of other persistent objects referring to the clone, and persistent relationships are not disturbed. To avoid references to persistent objects in the clone, a deep copy can be made in the clone method. Chapter 5 examines the clone method for an application data class.

As Chapter 5 explains, when a persistent object is serialized, persistent fields are loaded before the object's state is passed to the serialization stream. For that reason, serialization avoids all the potential problems of the makeTransient methods.

Applications that use JDO will find limited use for JDO-transient application data objects. In general, JDO-transient objects represent new objects that can be inserted into the datastore, or they represent unmanaged copies of persistent objects that already exist in the datastore. The most common reason that unmanaged copies of persistent objects arise is because serialization is producing them. Given the alternatives available, the application may not find a great deal of use for the makeTransient methods.




Using and Understanding Java Data Objects
Using and Understanding Java Data Objects
ISBN: 1590590430
EAN: 2147483647
Year: 2005
Pages: 156
Authors: David Ezzio

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net