Individual Object Caching

Whenever an object is fetched from the database or created by the user and registered with Cayenne, it is automatically cached. Accessing this object later (e.g. when traversing a relationship from another object, or doing a lookup by primary key via DataObjectUtils) will not incur an overhead of extra database access.

Synchronizing Objects on Commit

Very often there's more than one ObjectContext working over the same Cayenne stack. E.g. in a web application each user session may have its own ObjectContext. If one of the contexts commits its changes, Cayenne automatically updates copies of each modified object across all contexts ("copies" mean context-specific instances of objects with the same ObjectId). So all committed object changes become immediately visible to all contexts. If there's more than one Cayenne stack running (e.g. if the application is clustered across multiple JVMs), there are ways to notify other stacks about the object changes. This can be set up in the Modeler. However full synchronization of every change often results in excessive network traffic and CPU consumption, and is usually avoided in favor of the query cache approach described elsewhere in this chapter.

Memory Management

Cayenne ensures that the memory allocated to caching does not grow indefinitely. A cache shared between ObjectContexts has a fixed upper limit. 10000 is the default maximum number of entries, which can be changed in the Modeler. A cache attached to each ObjectContext (also referred to as "local cache" elsewhere in this chapter), which only stores the objects that were accessed via this context, has no upper limit. However it uses weak references to the cached committed objects, so they are automatically purged from cache when the application runs low on memory.


Object caching happens behind the scenes, so the only case when users need to worry about object cache is when an object gets stale and needs to get refreshed. Here are the strategies for refreshing a single stale object:

  • Perform a query to refetch one or more objects. Any of the Cayenne selecting queries would refresh previously cached objects:
    Artist a = ...;
    // "a" gets stale, we need to refresh it
    SelectQuery query = new SelectQuery(Artist.class, ...);
    List<Artist> artists = context.performQuery(query);
    // if the query result includes "a", object "a" is now refreshed
  • Use prefetching to refresh to-many relationships and related objects. Cayenne selecting query would only refresh the "root" objects (objects of type "Artist" in the example above), including their "simple" properties and to-one relationships. To refresh to-many relationships, including to-many collection contents, and each of the related objects, a user must specify a prefetch on a given relationship. E.g.:
    // to refresh a list of paintings attached to the Artist, use a prefetch:
  • Use ObjectIdQuery to refresh a single object. There is a special query that allows to refresh a single object - ObjectIdQuery. Specify "CACHE_REFRESH" caching strategy to ensure a DB fetch is performed. This requires manually creating an ObjectId:
    ObjectId id = new ObjectId("Artist", Artist.ID_PK_COLUMN, 5);
    ObjectIdQuery query = new ObjectIdQuery(id, false, ObjectIdQuery.CACHE_REFRESH);
    Artist a = (Artist) DataObjectUtils.objectForQuery(query);