of the transaction. If the transaction gets rolled back,
then the changes will be discarded; but if the transaction
commits, then the logical change summary contained in
the cache will be converted to SQL and committed to the
The vast majority of operations in most applications are
read operations. When there are no plans to modify the
object state, either within or outside a transaction, then a
globally shared cache is the most efficient mechanism for
obtaining the read-only state, even if it is deemed read-only for a temporary period.
A globally shared cache is accessible by all clients in the
same process space, whether or not they are in a transaction context. Some implementations even allow read-only operations to occur within a transaction, returning
nontransactional shared state instead of transactional
state. The motivation for doing so is usually performance,
since there is a nonzero cost to making an object transactional. The consequence of not following the rules,
however, could be severe. If the caller modifies an object,
previously assumed to be read-only, then its changes will
not be reflected in the database and the cached object will
end up in a corrupt and inconsistent state, containing
uncommitted updates outside the transaction.
t ra nsaction m anager
Even though transactional caches do not outlive the
transaction, retaining the changes contained in those
transactional caches is much more efficient. The sum
total of the object changes needs to be reflected in the
shared cache so that it can be kept up to date. If this
merge step were not done, then the versions of the
objects in the shared cache would be outdated or stale,
necessitating extra refresh operations from the database.
In the case of updates, then, the direction of update data
is from the transactional cache to the shared cache.
From the read perspective it works the opposite way.
When an object becomes transactional, the most recent
known state of the object can normally be obtained from
the shared cache; hence, the transactional cache acts as
a consumer of the shared cache in order to save itself a
trip to the database. Figure 1 is a diagrammatic view of
the exchange between the caches. Note that if the shared
cache cannot provide the object, then a database query
must be issued to obtain it, and the resulting object can
then be made available in the shared cache.
A general cache may accommodate one or multiple types
of cached structures, and the same holds true for ORM
caches. Although we have been referring to the ORM