Core Java Data Objects
4.1 A Persistent Object's Lifecycle
JDO defines seven required and three optional states: transient , persistent-new , persistent-new-deleted , hollow , persistent-clean , persistent-dirty , and persistent-deleted are the mandatory lifecycle states. Transient-dirty , transient-clean , and persistent-non-transactional are optional states and are explained later in this chapter. Some of the state transitions are directly triggered by the application itself ”for instance, making an object persistent. Starting or terminating a transaction can also trigger an object's state change, which might be invoked directly by the application developer through a call to Transaction methods begin() , commit() , or rollback() . Note that in managed environments, state changes can happen due to an external transaction controller. A persistence-capable instance can enter the JDO object lifecycle by two operations: a call to makePersistent or an instantiation by the JDO vendor's implementation when an existing object is loaded from a datastore. The chapter starts with two typical sequences making objects persistent and re-creating objects from the datastore. A short code sample is provided, and JDOHelper is used to gather information about the state changes in these sequences. 4.1.1 Making objects persistent
Operations to make an instance persistent follow the state diagram shown in Figure 4-1: Making transient instances persistent. Figure 4-1. Making transient instances persistent.
4.1.1.1 Transient
Instances of persistence-capable classes behave like any other Java objects when they are created by the new operator. Field access is not mediated for these objects, resulting in almost the same access performance as for unenhanced classes. Transient instances are not influenced by transactional methods like begin , commit , or rollback except when they are reachable by other persistent objects. 4.1.1.2 Persistent-new
A call to PersistenceManager.makePersistent() assigns a new object ID to the instance, and the state changes from transient to persistent-new. A persistent-new object behaves like a transient object, but is flushed to the datastore at commit or whenever the object state needs to be synchronized with internal caches. Its state is controlled by the JDO implementation. Other objects can have a persistent-new state if they are reachable through persistent fields. They are made persistent, and so on, until all reachable objects are either of a transient type or persistent-new. Between makePersistent() and a final commit, references may change and reachable instances may become unreachable. The state of these provisionally -persistent instances is also persistent-new. These objects behave like persistent-new objects, but their state may change during commit, if the provisionally -persistent object isn't reachable anymore. 4.1.1.3 Hollow
After successful completion of the transaction, the persistent-new object's state changes to hollow. A hollow object is a reference that represents some data in the datastore, which is not yet in memory or outdated . Usually, other clients or applications are free to access or change data in the datastore referenced by hollow objects ”for instance, in a different transaction, process, or JVM. Later, the application might access hollow objects, and the JDO implementation has to lazily reload data. This scenario is explained in the following section. Additionally, the contents of such hollow objects are cleared after commit, to free memory. If references were kept between hollow objects, the garbage collector may not free a graph of objects. After some transactions, a bunch of hollow objects might be accumulated . The hollow state cannot be interrogated by the application. There is no JDOHelper method, and access to fields may result in a state change so that it is impossible to tell the previous state. 4.1.1.4 Persistent-new-deleted
Whenever persistent-new objects are deleted by a call to PersistenceManager.deletePersistent() , their state changes to persistent-new-deleted. There is no way to undelete an object, which means that this state is final until transaction termination. Accessing a field of a deleted object results in a JDOUserException , except when reading primary-key fields. After transaction termination ( commit or rollback ), the deleted instance's state changes back to transient. 4.1.2 Creating objects from the datastore
The next steps explain typical state changes for instances that are initially loaded from the datastore, which is shown in Figure 4-2: Creating instances from the datastore. Figure 4-2. Creating instances from the datastore.
4.1.2.1 Hollow
As mentioned above, hollow is also the initial state for objects that are first created to represent a reference to data in a datastore, but the objects contain no valid data yet. When fields are accessed, data is retrieved on demand. Objects having the hollow state are instantiated by calls such as Extent.iterator().next() , PersistenceManager.getObjectById() , or a query execution. Usually, persistent fields of hollow objects are initialized to the field's default values (zero or null ), but because persistence-capable instances are created through their no-args constructors, they may be filled with other values as well. This might be the only visible difference between objects made hollow after they have been inserted in a previous transaction as mentioned in the preceding section and hollow objects that were created by the JDO implementation. 4.1.2.2 Persistent-clean
Objects transition from hollow to persistent-clean after they have been filled with valid data from the datastore, but only when the data has not yet been modified in the current transaction. The state is called clean because the object's data is consistent with the corresponding data in the datastore. Athough an object is filled with valid data by the JDO implementation, field references to other objects are resolved by the PersistenceManager. Either those references may point to objects already in memory, or the PersistenceManager creates new hollow objects. Persistent-clean objects might be collected by the JVM's garbage collector if the application no longer refers to the objects. The PersistenceManager is required to cache the references to objects and instantiate new hollow objects in case the objects were already garbage-collected . 4.1.2.3 Persistent-dirty
Objects transition from either persistent-clean or hollow to persistent-dirty when one of their persistent fields is changed. This state is called dirty because the in-memory data of the object does not reflect the persistent data corresponding to the object in the datastore. If the value assigned to a managed field is equal to the previous value, the instance's state nevertheless changes to persistent-dirty. Furthermore, an instance does not change back to persistent-clean or hollow when previous field values or modifications are restored. Whenever transient objects are assigned to persistent-clean or persistent-dirty objects, they do not transition to persistent-new at that moment. 4.1.2.4 Persistent-deleted
In a call to PersistentManager.deletePersistent() , the state of the persistent instance is changed to persistent-deleted. It is impossible to leave this state except by terminating the transaction, which means that there is no method to undo a deletePersistent call except by aborting the transaction. A successful transaction termination makes a deleted instance transient. An object cannot be made persistent again with the same identity as long as it is deleted. 4.1.3 Simplified lifecycle
The state diagram in Figure 4-3: Lifecycle: Mandatory states shows a simplified lifecycle. The marked area Read-OK encloses all states in which instances can be read (or accessed) without forcing a state change. Write-OK marks the same area for instance modification. Figure 4-3. Lifecycle: Mandatory states.
|