blob: aa3aab105240f6e62ab75cc408f813b0db28f11a [file] [log] [blame]
Title: Object Caching
<P>Cayenne implements an advanced caching mechanism that has a goal of improving application performance and ensuring data consistency both across Java applications and sessions within the same application. The following classes participate in the caching mechanism:</P>
<UL>
<LI><B>DataObject</B><BR>
Any persistent object; tracks the version of snapshot it was last updated with.</LI>
<LI><B>DataRow</B><BR>
Immutable snapshot of a database row. Has a VM-unique version identifier.</LI>
<LI><B>ObjectStore</B><BR>
Stores DataObjects using ObjectIds as keys.</LI>
<LI><B>DataRowStore</B><BR>
Stores snapshots as DataRows using ObjectIds as keys.</LI>
</UL>
<H3><A name="ObjectCaching-LevelsofCaching"></A>Levels of Caching</H3>
<P>Cayenne implements the following levels of caching:</P>
<UL>
<LI><B>Level 1 - No Cache Sharing</B><BR>
The DataContext keeps its own cache - data fetched from the database via a given DataContext is never shared with other local or remote DataContexts. Changes made on commit are not propagated to other DataContexts.<BR>
<SPAN class="image-wrap" style=""><IMG src="object-caching.data/cache-level1.gif" style="border: 0px solid black"></SPAN></LI>
<LI><B>Level 2 - Local VM Cache Sharing</B><BR>
Each DataDomain keeps the cache shared by all DataContexts in the same VM. Changes made via one of the DataContexts are propagated via a SnapshotEvent to other DataContexts in the same VM.<BR>
<SPAN class="image-wrap" style=""><IMG src="object-caching.data/cache-level2.gif" style="border: 0px solid black"></SPAN></LI>
<LI><B>Level 3 - Cross-VM Cache Sharing</B><BR>
Behaves just like Level 2, but also synchronizes caches across JVMs. SnapshotEvents are sent remotely via a preconfigured transport mechanism. Notification channels use the DataDomain name to identify which remote domains should receive the event.<BR>
<SPAN class="image-wrap" style=""><IMG src="object-caching.data/cache-level3.gif" style="border: 0px solid black"></SPAN></LI>
</UL>
<P>Caching properties are configured using CayenneModeler for each application DataDomain. Application code is normally independent from a chosen level, i.e., it does not have to be changed when caching is reconfigured. Details on caching configuration are provided in the <A href="configuring-caching-behavior.html" title="Configuring Caching Behavior">Modeler Guide</A>.</P>
<H3><A name="ObjectCaching-SynchronizingObjectStoresusingSnapshotEvents."></A>Synchronizing ObjectStores using SnapshotEvents.</H3>
<P>DataRowStore posts SnapshotEvents for any changes made to the cache. ObjectStore(s) using a given DataRowStore are automatically registered as listeners for SnapshotEvents and update their state accordingly. Application objects can also take advantage of the events by implementing SnapshotEventListener interface and registering with EventManager</P>
<DIV class="code panel" style="border-width: 1px;"><DIV class="codeContent panelContent">
<PRE class="code-java">SnapshotEventListener customListener = ...
DataDomain domain = Configuration.getSharedConfiguration().getDomain();
DataRowStore cache = domain.getSharedSnapshotCache();
domain.getEventManager().addListener(
customListener,
<SPAN class="code-quote">&quot;snapshotsChanged&quot;</SPAN>,
SnapshotEvent.class,
cache.getSnapshotEventSubject());
</PRE>
</DIV></DIV>
<DIV class="panelMacro"><TABLE class="noteMacro"><COLGROUP><COL width="24"><COL></COLGROUP><TR><TD valign="top"><IMG src="http://cayenne.apache.org/docs/1.2/images/icons/emoticons/warning.gif" width="16" height="16" align="absmiddle" alt="" border="0"></TD><TD><B>Upgrading to Cayenne 1.2 and Newer</B><BR>Cayenne 1.1 used a singleton EventManager accessible via <TT>EventManager.getDefaultManager()</TT>. Note that now EventManager is obtained from DataDomain or DataContext. Make sure that you register your listeners with an appropriate EventManager.</TD></TR></TABLE></DIV>
<H3><A name="ObjectCaching-ConcurrentUpdatesoftheSameDataObject."></A>Concurrent Updates of the Same DataObject.</H3>
<P>If two or more users update their local copies of the same object, Cayenne implements the following behavior:</P>
<UL>
<LI>Whenever a local modification of an object is detected, its snapshot is retained by ObjectStore, so that any changes to the underlying DataRowStore could not affect modification process of this object.</LI>
<LI>On commit, an UPDATE query is built based on retained snapshot, not the one currently cached in DataRowStore (this may or may not be the same DataRow). If the changes were made to a different set of attributes, this allows concurrent modification of the same object by different users without overwriting each other's changes.</LI>
<LI>Due to concurrency issues discussed above, if a snapshot version conflict occurs, DataRowStore removes a given snapshot from the cache to avoid dealing with concurrency effects on merging.</LI>
</UL>